-----------------------------------------------------------------------
Help Index System v1.0 by Xerves (September 14 2002)
Xerves is the admin/owner of Rafermand (mud.rafermand.net port 3002)
Website: http://www.rafermand.net
Contact: xerves@rafermand.net
-----------------------------------------------------------------------

Well this took a few days of work longer than I thought, but I have finally
finished it, and it is a giant dandy of a snippet.  This is by far the most
complicated snippet I have released so far (but might I add a very easy to
implement and use, just difficult to understand, laugh).  There are also two
phases of installing this.  You need to follow step 1 below to prep your
helpfiles for the transition, then you need to install the actual code in and
then do a reboot/copyover.  +++++++VERY IMPORTANT++++++++ Copy the backuped
helpfile (help.are.sbak) somewhere safe, like on a few floppy disks till you
start to use this system.  Once you go to the index, it might not be fun ripping
it out of a few hundred helpfiles.  So now that is out of the way, what the hell
is this snippet anyway?  Below is some output from hindex mage

******************************************************************************************
----------------------------Helpfiles in mage Index-----------------------------

imm bodybag                   remove invis                  acid breath                   
fire breath                   frost breath                  gas breath                    
lightning breath              

--------------------------------Indexes Above mage------------------------------

general                  

--------------------------------Indexes Below mage------------------------------

attack                   

-------------------------Full index above/below mage ---------------------------
******************************************************************************************

Above is an example of the hindex command.  This is used by typing hindex mage to
get a listing of all helpfiles in that index, and indexes above/below.  If you have
MXP support, all the helpfiles have links to them, all the indexes, and the words
"Full index" there at the bottom.  You can just click on them and it will run
the appropriate command.  In addition, you can see a full map of the index, and it
looks like this

******************************************************************************************
------------------------Full Map of the Index------------------------
general
               mage
                              attack
                                             gem
                                             test
imm
               attack
                              gem
                              test
******************************************************************************************

As you can see, it shows a map of the whole index layer by layer.  This one is
straight forward, but you can see two of the features of interest here.  You can
have more than one index at a certain level.  You can have Attack->Gem and also
Attack->Test.  This will allow you to group indexes that are similiar, but you
don't want to dump helpfiles into only 1.  In addition to this, you can see that
attack shows up twice, this is the product of cross-linking.  You can have one
index point to attack, and then have another.  The only problem with this is you
have to be careful because if you point it back ahead of the index, it is possible
for it to create a infinite loop.  So plan out your links before doing that. Below
is what you see with help frost breath

******************************************************************************************
'ACID BREATH' 'FIRE BREATH' 'FROST BREATH' 'GAS BREATH' 'LIGHTNING BREATH'
Syntax: cast 'acid breath'      <victim>
Syntax: cast 'fire breath'      <victim>
Syntax: cast 'frost breath'     <victim>
Syntax: cast 'gas breath'
Syntax: cast 'lightning breath' <victim>

These spells are for the use of dragons.  Acid, fire, frost, and lightning
damage one victim, whereas gas damages every PC in the room.  Fire and
frost can break objects, and acid can damage armor.

High level mages may learn and cast these spells as well.
 
Be aware that area attacks are aggressive to all mobs in the room,
including pets, mounts and charmed creatures.
Gas breath is an area attack, the other breath spells are not.

-------------------------Similiar Helpfiles in mage Index--------------------------

imm bodybag    remove invis    acid breath    fire breath    frost breath    
gas breath    lightning breath    
******************************************************************************************

Above is what you see with help frost breath.  As you notice, the typical helpfile information
comes up along with similiar helpfiles in that index (if that helpfile is in more than 1 index
all indexes will show up).  That brings us to another feature, multiple instances of a helpfile
in different indexes.  Say you have a skill that belongs in different classes, you are free to
put that skill in both classes indexes.  Also, there is a config called nosimiliar (config command)
to remove the list of helpfiles and instead just show all indexes that are linked to that helpfile.

Now that you have seen a good look of what it does, now time to get on with the business.

****************Step 1 - Setting up the Helpfile****************

You need to setup the helpfile to have all the helpfiles use the general group.  To do this, follow
the following directions

**************************
****File 1: Act_info.c****
**************************

Find the following lines in do_hset

   if ( str_cmp( arg1, "remove" ) )
	argument = one_argument( argument, arg2 );
	
Directly above them add this

   if (!str_cmp(arg1, "prepareindex"))
   {
      FILE *fpout;
      log_string_plus("Preparing help index and backuping up help.are...", LOG_NORMAL, LEVEL_STAFF); /* Tracker1 */   
      send_to_char("&w&RIT IS VERY IMPORTANT that you remove this function from do_hset in act_info.c after use.\n\rAlso save your old helpfile (backuped to help.are.sbak) somewhere safe\n\r", ch);
      
      rename("help.are", "help.are.sbak");
      fclose(fpReserve);
      if ((fpout = fopen("help.are", "w")) == NULL)
      {
         bug("hset save: fopen", 0);
         perror("help.are");
         fpReserve = fopen(NULL_FILE, "r");
         return;
      }

      fprintf(fpout, "#HELPS\n\n");
      for (pHelp = first_help; pHelp; pHelp = pHelp->next)
      {
         fprintf(fpout, "%d %s~\n", pHelp->level, pHelp->keyword);
         fprintf(fpout, "#%s~\n", HINDEX_GENERAL_NAME);
         fprintf(fpout, "#END~\n%s~\n\n", help_fix(pHelp->text));
      }

      fprintf(fpout, "0 $~\n\n\n#$\n");
      fclose(fpout);
      fpReserve = fopen(NULL_FILE, "r");
      send_to_char("Saved.\n\r", ch);
      return;
   }
   
Now, do a make and then do a copyover/reboot.  Once you login, you need to type the
command   hset prepareindex.  This will prepare your helpfiles to start to use this
system.  It will also create a backup of your old helpfiles under the new name of
help.are.sbak.  I would put that file in a safe place for the time being.  Now
that this is done, DO NOT REBOOT, wait till you install the following code first.

****************Step 2 - Installing the Code****************

**************************
****File 1: Act_info.c****
**************************

Find this near the top

   void    show_condition          args( ( CHAR_DATA *ch, CHAR_DATA *victim ) );
   
Directly below it add this

   int showcollapse;
   
Find do_help function
   
   void do_help(CHAR_DATA * ch, char *argument)
   
Right above it add this

//maxlength should not be over 25
char *add_wspace(int length, int maxlength)
{
   int x = maxlength - length;
   static char wbuf[30];
   strcpy(wbuf, "");
   
   if (length >= maxlength)
   {
      return "";
   }
   else
   {
      for(;;)
      {     
         strcat(wbuf, " ");     
         if (--x == 0)
            break;
      }
   }
   return wbuf;
}

Now, replace the whole do_help function you just found with this one

void do_help(CHAR_DATA * ch, char *argument)
{
   HELP_DATA *pHelp;
   HINDEX_DATA *hindex;
   HINDEX_POINTER *hpointer;
   HINDEX_IPOINTER *hipointer;
   HELP_DATA *ihelp;
   char helpfile[100];
   char arg[MAX_INPUT_LENGTH];
   int cnt;
   int nshow = 0;
   char *helpstring;

   one_argument(argument, arg);
   
   if (!str_cmp(arg, "_clean_"))
   {
      nshow = 1;
      argument = one_argument(argument, arg);
   }   

   if ((pHelp = get_help(ch, argument)) == NULL)
   {
      pager_printf_color( ch, "&C&wNo help on \'%s\' found.\n\r", argument );
      return;
   }

   /* Make newbies do a help start. --Shaddai */
   if (!IS_NPC(ch) && !str_cmp(argument, "start"))
      SET_BIT(ch->pcdata->flags, PCFLAG_HELPSTART);

   if (pHelp->level >= 0 && str_cmp(argument, "imotd"))
   {
      send_to_pager(pHelp->keyword, ch);
      send_to_pager("\n\r", ch);
   }

   /*
    * Strip leading '.' to allow initial blanks.
    */
   if (pHelp->text[0] == '.')
      send_to_pager_color(pHelp->text + 1, ch);
   else
      send_to_pager_color(pHelp->text, ch);
      
   //HelpIndex Code Below
   if (!xIS_SET(ch->act, PLR_NOSIMILIAR) && nshow == 0)
   {
      for (hpointer = pHelp->first_hindex; hpointer; hpointer = hpointer->next)
      {
         cnt = 0;
         hindex = hpointer->pointer;
         #ifdef HINDEX_MXP  
            ch_printf(ch, "\n\r&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&CSimiliar Helpfiles in " MXPTAG ("hindex '%s'") "%s" MXPTAG ("/hindex") " Index&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-\n\r\n\r", hindex->keyword, hindex->keyword);
         #else
            ch_printf(ch, "\n\r&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&CSimiliar Helpfiles in %s Index&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-\n\r\n\r", hindex->keyword);    
         #endif
         for (hipointer = hindex->first_help; hipointer; hipointer = hipointer->next)
         {
            ihelp = hipointer->pointer;
            helpstring = ihelp->keyword;
            for (;;)
            {
               if (helpstring[0] == '\0')
                  break;
               else
               {
                  helpstring = one_argument(helpstring, helpfile);
                  if (cnt + strlen(helpfile) > 76)
                  {
                     send_to_char("\n\r", ch);
                     cnt = 0;
                  }
                  #ifdef HINDEX_MXP  
                     ch_printf(ch, MXPTAG ("help '%s'") "&w&R%s"  MXPTAG ("/help") "    ", helpfile, helpfile);
                  #else
                     ch_printf(ch, "&w&R%s    ", helpfile);
                  #endif
                  cnt+= strlen(helpfile) + 4;
               }
            }
         }  
         send_to_char("\n\r", ch);   
      }
   }
   else if (xIS_SET(ch->act, PLR_NOSIMILIAR) && nshow == 0)
   {
      cnt = 0;
      ch_printf(ch, "\n\r&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&CHelpIndex(es) for %s&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-\n\r\n\r", pHelp->keyword);
      for (hpointer = pHelp->first_hindex; hpointer; hpointer = hpointer->next)
      {
         hindex = hpointer->pointer;
         if (cnt + strlen(hindex->keyword) > 76)
         {
             send_to_char("\n\r", ch);
             cnt = 0;
         }
         #ifdef HINDEX_MXP  
            ch_printf(ch, MXPTAG ("hindex '%s'") "&w&W%s"  MXPTAG ("/hindex") "    ", hindex->keyword, hindex->keyword);
         #else
            ch_printf(ch, "&w&W%s    ", hindex->keyword);
         #endif
         cnt+= strlen(hindex->keyword) + 4;  
      }
      send_to_char("\n\r", ch);
   } 
   return;
}

In do_hedit find the following lines
   
        CREATE(pHelp, HELP_DATA, 1);
        pHelp->keyword = STRALLOC(strupper(argument));
        pHelp->text = STRALLOC("");
        pHelp->level = lev;
        
Directly below add this
   
        //Add it into the general index...
        parse_helpfile_index(NULL, pHelp, HINDEX_GENERAL_NAME);
        
Find the function do_hset down a little bit, replace the whole function with these functions below

/* Used in hindex to do varius functions, it is controlled by the use value
0 - Show full map
1 - Search for a value
2 - Output for collapse
*/
HINDEX_DATA *hindex_search_function(int level, CHAR_DATA *ch, HINDEX_DATA *hindex, HINDEX_DATA *tindex, char *argument, int use)
{
   char sbuf[200];
   int cnt = 0;
   int ddown = 0;
   int dnext = 0;
   HINDEX_DATA *rvalue = NULL;
   
   if (use == 0)
   {
      strcpy(sbuf, "");   
      for (;;)
      {
         if (cnt < level)
         {
            strcat(sbuf, "               ");
         }
         else
            break;
         cnt++;
      }
      #ifdef HINDEX_MXP  
         ch_printf(ch, "%s" MXPTAG("hindex '%s'") "&w&W%s\n\r" MXPTAG("/hindex"), sbuf, hindex->keyword, hindex->keyword); 
      #else
         ch_printf(ch, "&w&W%s%s\n\r", sbuf, hindex->keyword); 
      #endif
   }
   if (use == 1)
   {
      if (!str_cmp(hindex->keyword, argument))
         return hindex;
   }
   if (use == 2)
   {
      sprintf(sbuf, "%s collapse", hindex->keyword);
      do_hindex(ch, sbuf);
   }
      
   for (;;)
   {   
      if (hindex->first_hindex && ddown == 0)   
      {
         rvalue = hindex_search_function(level+1, ch, hindex->first_hindex, hindex, argument, use);
         if (rvalue && use == 1)
            return rvalue;
         ddown = 1;
      }
      else if (hindex->next && dnext == 0)
      {
         rvalue = hindex_search_function(level, ch, hindex->next, tindex, argument, use);
         if (rvalue && use == 1)
            return rvalue;
         dnext = 1;
      }
      else
         return rvalue; //Go back up a level or finally exit
   }
}
   
void do_hindex(CHAR_DATA * ch, char *argument)
{
   HINDEX_DATA *hindex;
   HINDEX_DATA *oindex;
   HINDEX_IPOINTER *hipointer;
   HELP_DATA *help;
   int cnt = -1;
   char helpfile[100];
   char *helpstring;
   char arg[MAX_INPUT_LENGTH];
   char arg2[MAX_INPUT_LENGTH];
   
   if (argument[0] == '\0')
   {
      #ifdef HINDEX_MXP  
         send_to_char("Syntax:  " MXPTAG ("hindex toplevel")"hindex toplevel\n\r" MXPTAG ("/hindex"), ch);
         send_to_char("Syntax:  hindex <index> [nohfiles/collapse]\n\r", ch);
         send_to_char("Syntax:  " MXPTAG ("hindex map")"hindex map\n\r" MXPTAG ("/hindex"), ch);
         send_to_char("Help hindex for more information\n\r", ch);
      #else
         send_to_char("Syntax:  hindex toplevel\n\r", ch);
         send_to_char("Syntax:  hindex <index> [nohfiles/collapse]\n\r", ch);
         send_to_char("Syntax:  hindex map\n\r", ch);
         send_to_char("Help hindex for more information\n\r", ch);
      #endif
      return;
   }
   argument = one_argument(argument, arg);
   
   if (!str_cmp(arg, "toplevel"))//Show only the top level indexes, no helpfiles
   {
      send_to_char("&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&CTop Level of the Index&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-\n\r", ch);
      for (hindex = first_hindex; hindex; hindex = hindex->next)
      {
         cnt++;
         if (cnt % 3 == 0)
            send_to_char("\n\r", ch);
         #ifdef HINDEX_MXP
            ch_printf(ch, MXPTAG ("hindex '%s'") "&w&R%s" MXPTAG ("/hindex") "%s", hindex->keyword, hindex->keyword, add_wspace(strlen(helpfile), 25));
         #else
            ch_printf(ch, "&w&R%s%s", hindex->keyword, add_wspace(strlen(helpfile), 25));   
         #endif
      }
      send_to_char("\n\r", ch);
      return;
   }
   if (!str_cmp(arg, "map"))//Show a map of the index top to bottom
   {
      send_to_char("&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&CFull Map of the Index&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-\n\r", ch);
      hindex_search_function(0, ch, first_hindex, NULL, NULL, 0); //Need to do this because I need multiple variables to hold the loop
      return;
   }
   if ((hindex = hindex_search_function(0, ch, first_hindex, NULL, arg, 1)) != NULL) //Need to do this because I need multiple variables to hold the loop)
   {     
      if (argument[0] == '\0') //do not collapse, show helpfiles
      {
         #ifdef HINDEX_MXP
            ch_printf(ch, "&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&CHelpfiles in " MXPTAG ("hindex '%s'") "%s" MXPTAG ("/hindex") " Index&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-\n\r", hindex->keyword, hindex->keyword);
         #else
            ch_printf(ch, "&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&CHelpfiles in %s Index&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-\n\r", hindex->keyword);   
         #endif
         {
            for (hipointer = hindex->first_help; hipointer; hipointer = hipointer->next)
            {
               help = hipointer->pointer;
               helpstring = help->keyword;
               for (;;)
               {
                  if (helpstring[0] == '\0')
                     break;
                  else
                  {
                     helpstring = one_argument(helpstring, helpfile);
                     cnt++;
                     if (cnt % 3 == 0)
                        send_to_char("\n\r", ch);
                     #ifdef HINDEX_MXP   
                        ch_printf(ch, MXPTAG ("help '%s'") "&w&R%s"  MXPTAG ("/help") "%s", helpfile, helpfile, add_wspace(strlen(helpfile), 25));
                     #else
                        ch_printf(ch, "&w&R%-25s     ", helpfile);
                     #endif
                  }
               }
            }
            cnt = -1;
            ch_printf(ch, "\n\r\n\r&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&CIndexes Above %s&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-\n\r", hindex->keyword);
            for (oindex = hindex->first_top_hindex; oindex; oindex = oindex->tnext)
            {
               cnt++;
               if (cnt % 3 == 0)
                  send_to_char("\n\r", ch);
               #ifdef HINDEX_MXP
                  ch_printf(ch, MXPTAG ("hindex '%s'") "&c&w%s" MXPTAG ("/hindex") "%s", oindex->keyword, oindex->keyword, add_wspace(strlen(oindex->keyword), 25));
               #else
                  ch_printf(ch, "&c&w%s%s", oindex->keyword, add_wspace(strlen(oindex->keyword), 25));
               #endif
            }  
            cnt = -1;
            ch_printf(ch, "\n\r\n\r&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&CIndexes Below %s&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-\n\r", hindex->keyword);
            for (oindex = hindex->first_hindex; oindex; oindex = oindex->next)
            {
               cnt++;
               if (cnt % 3 == 0)
                  send_to_char("\n\r", ch);
               #ifdef HINDEX_MXP
                  ch_printf(ch, MXPTAG ("hindex '%s'") "&w&W%s" MXPTAG ("/hindex") "%s", oindex->keyword, oindex->keyword, add_wspace(strlen(oindex->keyword), 25));
               #else
                  ch_printf(ch, "&w&W%s%s", oindex->keyword, add_wspace(strlen(oindex->keyword), 25));
               #endif
            }         
            send_to_char("\n\r", ch);    
            #ifdef HINDEX_MXP
               ch_printf(ch, "\n\r&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-"MXPTAG ("hindex map")"&w&CFull index" MXPTAG ("/hindex") " &w&Cabove/below %s &w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-\n\r", hindex->keyword, hindex->keyword);
            #endif
            return; 
         }
      }
      argument = one_argument(argument, arg2);
      if ((!str_cmp(arg2, "nohfiles") && !str_cmp(argument, "collapse")) || (!str_cmp(arg2, "collapse") && !str_cmp(argument, "nohfiles")))
      {
         send_to_char("You can only choose one, not both.\n\r", ch);
         return;
      }
      if (!str_cmp(arg2, "nohfiles")) //Show only the index
      {
         ch_printf(ch, "&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&W-&w&CFull Index Below %s&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-\n\r", hindex->keyword);
            hindex_search_function(0, ch, hindex, NULL, NULL, 0); 
      }
      if (!str_cmp(arg2, "collapse")) //Show the complete index below this one + Helpfiles
      {  
         if (showcollapse == 0)
         {
            ch_printf(ch, "&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&W-&w&CFull Index Below %s&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-\n\r", hindex->keyword);
            hindex_search_function(0, ch, hindex, NULL, NULL, 0); 
            
            showcollapse = 1;
            hindex_search_function(0, ch, hindex, NULL, NULL, 2); 
            showcollapse = 0;
            send_to_char("\n\r", ch);
            return;
         }
         else
         {
            cnt = -1;
            #ifdef HINDEX_MXP
               ch_printf(ch, "\n\r&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&CHelpfiles in " MXPTAG ("hindex '%s'") "%s" MXPTAG ("/hindex") " Index&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-\n\r", hindex->keyword, hindex->keyword);
            #else
               ch_printf(ch, "\n\r&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&CHelpfiles in %s Index&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-&w&W-&w&c-\n\r", hindex->keyword);
            #endif
            for (hipointer = hindex->first_help; hipointer; hipointer = hipointer->next)
            {
               help = hipointer->pointer;
               helpstring = help->keyword;
               for (;;)
               {
                  if (helpstring[0] == '\0')
                     break;
                  else
                  {
                     helpstring = one_argument(helpstring, helpfile);
                     cnt++;
                     if (cnt % 3 == 0)
                        send_to_char("\n\r", ch);
                     #ifdef HINDEX_MXP
                        ch_printf(ch, MXPTAG ("help '%s'") "&w&R%s"  MXPTAG ("/help") "%s", helpfile, helpfile, add_wspace(strlen(helpfile), 25));
                     #else
                        ch_printf(ch, "&w&R%-25s     ", helpfile);
                     #endif
                  }
               }
            }
            send_to_char("\n\r", ch);
            return;
         }
      }
   }
   else
   {
      send_to_char("That is not an available index, if you cannot find one, view them all with hindex map.\n\r", ch);
      return;
   }
} 

HINDEX_DATA *get_hindex_name(char *argument, HELP_DATA *help)
{
   char index[100];
   HINDEX_DATA *hindex = NULL;
   HINDEX_POINTER *hpointer;
   
   for (;;) //Get the index's name
   {
      argument = one_argument(argument, index);
      if (argument[0] == '\0')
         break;
   }
   for (hpointer = help->first_hindex; hpointer; hpointer = hpointer->next)
   {
      if (!str_cmp(hpointer->pointer->keyword, index))
      {
         hindex = hpointer->pointer;
         break;
      }
   }
   if (!hindex)
   {
      bug("Hindex %s in helpfile %s is invalid", index, help->keyword);
      return NULL;
   }
   return hindex;
}

HINDEX_POINTER *get_hindex_pointer(HINDEX_DATA *hindex, HINDEX_POINTER *first)
{
   HINDEX_POINTER *hpointer;
   for (hpointer = first; hpointer; hpointer = hpointer->next)
   {
      if (hpointer->pointer == hindex)
         break;
   }
   if (!hpointer)
   {
      bug("hpointer error in helpfile %s", hindex->keyword);
      return NULL;
   }
   return hpointer;
}

   
void do_hset(CHAR_DATA * ch, char *argument)
{
   HELP_DATA *pHelp;
   HINDEX_NAME *hname;
   HINDEX_POINTER *hpointer = NULL;
   HINDEX_POINTER *chpointer = NULL;
   HINDEX_IPOINTER *hipointer;
   char buf[300];
   char arg1[MAX_INPUT_LENGTH];
   char arg2[MAX_INPUT_LENGTH];
   char arg3[MAX_INPUT_LENGTH];
   char arg4[MAX_INPUT_LENGTH];

   smash_tilde(argument);
   argument = one_argument(argument, arg1);
   if (arg1[0] == '\0')
   {
      send_to_char("Syntax: hset <field> [value] [help page]\n\r", ch);
      send_to_char("\n\r", ch);
      send_to_char("Field being one of:\n\r", ch);
      send_to_char("  level keyword remove save\n\r", ch);
      send_to_char("------------------------------------------------\n\r", ch);
      send_to_char("Syntax: hset hindex <help page> view\n\r", ch);
      send_to_char("Syntax: hset hindex <help page> place <help index name>\n\r", ch);
      send_to_char("Syntax: hset hindex <help page> create <help index name>\n\r", ch);
      send_to_char("Syntax: hset hindex <help page> delete <number>\n\r", ch);
      send_to_char("Syntax: hset hindex <help page> shift <number> <up/down>\n\r", ch);
      send_to_char("Syntax: hset hindex crosslink <recepient index> <target index>\n\r", ch);
      send_to_char("------------------------------------------------\n\r", ch);
      return;
   }
   
   if (!str_cmp(arg1, "hindex"))
   {
      HINDEX_DATA *hindex;
      HINDEX_DATA *chindex;
      HINDEX_NAME *chname;
      int value = 0;
      int cnt = 1;
      
      argument = one_argument(argument, arg2);
      argument = one_argument(argument, arg3);
      if (!str_cmp(arg2, "crosslink"))
      {
         for (hindex = first_fhindex; hindex; hindex = hindex->fnext)
         {
            if (!str_cmp(arg3, hindex->keyword))
               break;
         }
         if (!hindex)
         {
            ch_printf(ch, "%s does not exist as an index.\n\r", arg3);
         }
         for (chindex = first_fhindex; chindex; chindex = chindex->fnext)
         {
            if (!str_cmp(argument, chindex->keyword))
               break;
         }
         if (!chindex)
         {
            ch_printf(ch, "%s does not exist as an index.\n\r", argument);
         }
         LINK(chindex, hindex->first_hindex, hindex->last_hindex, next, prev);
         LINK(hindex, chindex->first_top_hindex, chindex->last_top_hindex, tnext, tprev);
         ch_printf(ch, "%s has been linked below %s, might check hindex map to make sure it doesn't loop.\n\r", argument, arg3);
         return;
      } 
                 
      if ((pHelp = get_help(ch, arg2)) == NULL)
      {
         send_to_char("There is no helpfile available by that name.\n\r", ch);
         return;
      }
      if (!str_cmp(arg3, "view")) //Limited information compared to hindex, mainly to get the number for delete
      {
         for (hname = pHelp->first_iname; hname; hname = hname->next)
         {   
            ch_printf(ch, "%-2d>  %s\n\r", cnt++, hname->name);
         }
         return;
      }
      if (!str_cmp(arg3, "create")) //Cannot exist, will create a new one :-)
      {
         sprintf(buf, argument);
         for (;;)
         {
            argument = one_argument(argument, arg4);
            if (argument[0] != '\0')
               continue;
            else //time to do a name check to make sure it exists
            {
               for (hindex = first_fhindex; hindex; hindex = hindex->fnext)
               {
                  if (!str_cmp(arg4, hindex->keyword))//Alright can add this helpfile now
                  {
                     ch_printf(ch, "%s already exists and therefore cannot be created\n\r", arg4);
                     return;
                  }
               }
               if (!hindex)
               {
                  argument = &buf[0];
                  parse_helpfile_index(NULL, pHelp, argument);
                  ch_printf(ch, "%s has been created and %s added to it!\n\r", arg4, arg2);
                  return;
               }
            }
         }
      }      
      if (!str_cmp(arg3, "place")) //Has to exist, mainly for error checking and level seperation for the two...
      {
         sprintf(buf, argument);
         for (;;)
         {
            argument = one_argument(argument, arg4);
            if (argument[0] != '\0')
               continue;
            else //time to do a name check to make sure it exists
            {
               for (hindex = first_fhindex; hindex; hindex = hindex->fnext)
               {
                  if (!str_cmp(arg4, hindex->keyword))//Alright can add this helpfile now
                  {
                     CREATE(hipointer, HINDEX_IPOINTER, 1);
                     hipointer->pointer = pHelp;
                     LINK(hipointer, hindex->first_help, hindex->last_help, next, prev);
                     CREATE(hpointer, HINDEX_POINTER, 1);
                     hpointer->pointer = hindex;
                     LINK(hpointer, pHelp->first_hindex, pHelp->last_hindex, next, prev);
                     CREATE(hname, HINDEX_NAME, 1);
                     hname->name = STRALLOC(buf);
                     LINK(hname, pHelp->first_iname, pHelp->last_iname, next, prev); 
                     ch_printf(ch, "%s has been placed in %s\n\r", arg2, arg4);
                     return;
                  }
               }
               if (!hindex)
               {
                  ch_printf(ch, "%s is an index that does not exist\n\r", arg4);
                  return;
               }
            }
         }
      }                     
      argument = one_argument(argument, arg4);    
      if (!str_cmp(arg3, "shift")) //Shift the help index up/down on a helpfile
      {
         value = atoi(arg4);
         if (!value)
         {
            send_to_char("You need to specify the number listed in view.\n\r", ch);
            return;
         }
         cnt = 1;
         if (!str_cmp(argument, "down"))
         {
            value = 0;
            for (hname = pHelp->first_iname; hname; hname = hname->next)
            {
               value++;
            }
            if (atoi(arg4) == value)
            {
               send_to_char("You cannot shift that down, it is at the bottom.\n\r", ch);
               return;
            }
            value = atoi(arg4);
            for (hname = pHelp->first_iname; hname; hname = hname->next)
            {
               if (cnt++ == value)
               {
                  if ((hindex = get_hindex_name(hname->name, pHelp)) == NULL)
                  {
                     send_to_char("There was a bug, notify an immortal if one doesn't know already.\n\r", ch);
                     return;
                  }
                  if ((hpointer = get_hindex_pointer(hindex, pHelp->first_hindex)) == NULL)
                  {
                     send_to_char("There was a bug, notify an immortal if one doesn't know already.\n\r", ch);
                     return;
                  }
                  break;
               }
            }
            if (!hname)
            {
               ch_printf(ch, "That is not in the valid range.\n\r", ch);
               return;
            }
            cnt = 1;
            for (chname = pHelp->first_iname; chname; chname = chname->next)
            {
               if (cnt++ == value+1)
               {
                  if ((chindex = get_hindex_name(chname->name, pHelp)) == NULL)
                  {
                     send_to_char("There was a bug, notify an immortal if one doesn't know already.\n\r", ch);
                     return;
                  }
                  if ((chpointer = get_hindex_pointer(chindex, pHelp->first_hindex)) == NULL)
                  {
                     send_to_char("There was a bug, notify an immortal if one doesn't know already.\n\r", ch);
                     return;
                  }
                  break;
               }
            }
            if (!hname)
            {
               ch_printf(ch, "That is not in the valid range.\n\r", ch);
               return;
            }
            SHIFT_DOWN(hname, chname, pHelp->last_iname);
            SHIFT_DOWN(hpointer, chpointer, pHelp->last_hindex); 
              
            ch_printf(ch, "%d is shifted below %d.\n\r", value, value+1);
            return;
         }
                 
         if (!str_cmp(argument, "up"))
         {
            if (value == 1)
            {
               ch_printf(ch, "You cannot shift that up, it is number 1 in the list.\n\r", ch);
               return;
            }
            for (hname = pHelp->first_iname; hname; hname = hname->next)
            {
               if (cnt++ == value)
               {
                  if ((hindex = get_hindex_name(hname->name, pHelp)) == NULL)
                  {
                     send_to_char("There was a bug, notify an immortal if one doesn't know already.\n\r", ch);
                     return;
                  }
                  if ((hpointer = get_hindex_pointer(hindex, pHelp->first_hindex)) == NULL)
                  {
                     send_to_char("There was a bug, notify an immortal if one doesn't know already.\n\r", ch);
                     return;
                  }
                  break;
               }
            }
            if (!hname)
            {
               ch_printf(ch, "That is not in the valid range.\n\r", ch);
               return;
            }
            cnt = 1;
            for (chname = pHelp->first_iname; chname; chname = chname->next)
            {
               if (cnt++ == value-1)
               {
                  if ((chindex = get_hindex_name(chname->name, pHelp)) == NULL)
                  {
                     send_to_char("There was a bug, notify an immortal if one doesn't know already.\n\r", ch);
                     return;
                  }
                  if ((chpointer = get_hindex_pointer(chindex, pHelp->first_hindex)) == NULL)
                  {
                     send_to_char("There was a bug, notify an immortal if one doesn't know already.\n\r", ch);
                     return;
                  }
                  break;
               }
            }
            if (!chname)
            {
               ch_printf(ch, "That is not in the valid range.\n\r", ch);
               return;
            }
            SHIFT_UP(hname, chname, pHelp->first_iname);
            SHIFT_UP(hpointer, chpointer, pHelp->first_hindex); 
            /*
            if (pHelp->first_iname == chname) 
               pHelp->first_iname = hname;
              
            hname->next = chname->next;
            if (hname->next)
               hname->next->prev = hname;
            chname->prev = hname->prev;
            if (chname->prev)
               chname->prev->next = chname;
            
            hname->prev = chname;
            chname->next = hname; */
            ch_printf(ch, "%d is shifted above %d.\n\r", value, value-1);
            return;
         }
      }
      if (!str_cmp(arg3, "delete"))
      {
         for (hname = pHelp->first_iname; hname; hname = hname->next)
         { 
            if (cnt++ == atoi(arg4)) //Delete out this hindex from the helpfile, it DOES NOT delete the hindex.  Reboot/copyover to do this
            {
               hindex = get_hindex_name(hname->name, pHelp);
               if (!hindex)
               {
                  send_to_char("There was a bug, notify an immortal if one doesn't know already.\n\r", ch);
                  return;
               }
               for (hpointer = pHelp->first_hindex; hpointer; hpointer = hpointer->next)
               {
                  if (hpointer->pointer == hindex)
                  {
                     break;
                  }
               }
               if (!hpointer)
               {
                  bug("Helpfile %s is not pointing correctly to a hindex", pHelp->keyword);
                  send_to_char("There was a bug, notify an immortal if one doesn't know already.\n\r", ch);
                  return;
               }  
               for (hipointer = hindex->first_help; hipointer; hipointer = hipointer->next)
               {
                  if (hipointer->pointer == pHelp)
                  {
                     break;
                  }
               }
               if (!hipointer)
               {
                  bug("Helpfile %s is not showing up in a hindex", pHelp->keyword);
                  send_to_char("There was a bug, notify an immortal if one doesn't know already.\n\r", ch);
                  return;
               }  
               ch_printf(ch, "%s was removed from the helpfile and the helpfile from the index.\n\r", hname->name);
               UNLINK(hipointer, hindex->first_help, hindex->last_help, next, prev);
               UNLINK(hpointer, pHelp->first_hindex, pHelp->last_hindex, next, prev);
               STRFREE(hname->name);
               UNLINK(hname, pHelp->first_iname, pHelp->last_iname, next, prev);
               return;
            }
         }
         send_to_char("That is not a valid number.\n\r", ch);
         return;
      }
   } 
   if (!str_cmp(arg1, "save"))
   {
      FILE *fpout;

      log_string_plus("Saving help.are...", LOG_NORMAL, LEVEL_STAFF); /* Tracker1 */

      rename("help.are", "help.are.bak");
      fclose(fpReserve);
      if ((fpout = fopen("help.are", "w")) == NULL)
      {
         bug("hset save: fopen", 0);
         perror("help.are");
         fpReserve = fopen(NULL_FILE, "r");
         return;
      }

      fprintf(fpout, "#HELPS\n\n");
      for (pHelp = first_help; pHelp; pHelp = pHelp->next)
      {
         fprintf(fpout, "%d %s~\n", pHelp->level, pHelp->keyword);
         if (!pHelp->first_iname)
            fprintf(fpout, "#%s~\n", HINDEX_GENERAL_NAME);
         else
         {
            for (hname = pHelp->first_iname; hname; hname = hname->next)
               fprintf(fpout, "#%s~\n", hname->name);
         }
         fprintf(fpout, "#END~\n%s~\n\n", help_fix(pHelp->text));
      }

      fprintf(fpout, "0 $~\n\n\n#$\n");
      fclose(fpout);
      fpReserve = fopen(NULL_FILE, "r");
      send_to_char("Saved.\n\r", ch);
      return;
   }
   if (str_cmp(arg1, "remove"))
      argument = one_argument(argument, arg2);

   if ((pHelp = get_help(ch, argument)) == NULL)
   {
      send_to_char("Cannot find help on that subject.\n\r", ch);
      return;
   }
   if (!str_cmp(arg1, "remove"))
   {
      UNLINK(pHelp, first_help, last_help, next, prev);
      STRFREE(pHelp->text);
      STRFREE(pHelp->keyword);
      DISPOSE(pHelp);
      send_to_char("Removed.\n\r", ch);
      return;
   }
   if (!str_cmp(arg1, "level"))
   {
      pHelp->level = atoi(arg2);
      send_to_char("Done.\n\r", ch);
      return;
   }
   if (!str_cmp(arg1, "keyword"))
   {
      STRFREE(pHelp->keyword);
      pHelp->keyword = STRALLOC(strupper(arg2));
      send_to_char("Done.\n\r", ch);
      return;
   }

   do_hset(ch, "");
}
        
Now find the following lines in do_config

   set_char_color(AT_DGREEN, ch);
   send_to_char("\n\r\n\rSettings:  ", ch);
   
Right before them add this (Note:  I put this on an empty line, format it to your liking later)

   ch_printf(ch, "\n\r%-12s", xIS_SET(ch->act, PLR_NOSIMILIAR) ? "[+] SHORTHELP" : "[-] shorthelp");
   
Find this down a bit more

           bit = PLR_COMBINE;
        else if (!str_cmp(arg + 1, "prompt"))
           bit = PLR_PROMPT;
           
Below that add the following

        else if (!str_cmp(arg + 1, "shorthelp"))
           bit = PLR_NOSIMILIAR;


***********************
****File 2: Build.c****
***********************

Find this in build.c
 
    litterbug
    
This is the list of act flags, at the very end of the list - before the };  - Add the following

   , "nofamiliar"
   
Make sure to put that after the last item and before the );

**********************
****File 3: Comm.c****
**********************

If you are going to be using MXP AND you have installed Gammon's snippet support, find the following
in comm.c

        /* List an item tag (for things in a shop) */
     write_to_buffer( d, MXPTAG 
         ("!ELEMENT List \"<send href='buy &#39;&name;&#39;' "
         
Above it add the following

     // Click on a helpfile to view it
     write_to_buffer( d, MXPTAG
         ("!ELEMENT Help \"<send href='help &#39;&name;&#39;' "
          "hint='Help &name;'>\" "
          "ATT='name'"),
          0);
     // Click on a help index to view it
     write_to_buffer( d, MXPTAG
         ("!ELEMENT Hindex \"<send href='hindex &#39;&name;&#39;' "
          "hint='hindex &name;'>\" "
          "ATT='name'"),
          0);

Next, this might be tricky, laugh.  Any do_help call in comm.c or anywhere else
that you don't want to show any of the index information (like motd) you need to
do this

   do_help(ch, "_clean_ motd");
   
All you need to do is add _clean_ before the keyword.  You don't have to add that
helpfile (you shouldn't).  You will want to search for motd amotd imotd and nmotd
and do similiar things to them.

********************
****File 4: Db.c****
********************

Find this near the top of db.c

  HELP_DATA *first_help;
  HELP_DATA *last_help;

Right Below it add this

  HINDEX_DATA *first_hindex;
  HINDEX_DATA *last_hindex;
  
  HINDEX_DATA *first_fhindex; //First flat hindex
  HINDEX_DATA *last_fhindex; //Last flat hindex
  
Find the function load_helps, replace it with the following functions

int parse_helpfile_index(FILE *fp, HELP_DATA *pHelp, char *argument)
{
   HINDEX_DATA * hindex = NULL;
   HINDEX_DATA * hindex2;
   HINDEX_DATA *findex;
   HINDEX_NAME * hiname;
   HINDEX_POINTER *hpointer;
   HINDEX_IPOINTER *hipointer;
   HELP_DATA *help;
   char keyword[100];
   char fullkeyword[200];
   int value = 0;
   char *keystring;
   
   //if there is a file pointer, then it is being read from file, if not, it is being used in hset
   if (fp)
   {
      keystring = fread_string(fp);
      if (keystring[0] != '#')
         return 1;
      keystring++; //advance past the #
      sprintf(fullkeyword, "%s", keystring);
      keystring = one_argument(keystring, keyword);
      if (!str_cmp(keyword, "END"))
         return 0;
   }
   else
   {
      sprintf(fullkeyword, argument);
      keystring = argument;
      keystring = one_argument(keystring, keyword);
   }
   CREATE(hiname, HINDEX_NAME, 1);
   hiname->name = STRALLOC(fullkeyword);
   LINK(hiname, pHelp->first_iname, pHelp->last_iname, next, prev);
   
   if (!first_hindex)
   {
      CREATE(hindex, HINDEX_DATA, 1);
      hindex->keyword = STRALLOC(keyword);
      hindex->first_help = NULL;
      hindex->last_help = NULL;
      hindex->first_hindex = NULL;
      hindex->last_hindex = NULL;
      LINK(hindex, first_hindex, last_hindex, next, prev);
      LINK(hindex, first_fhindex, last_fhindex, fnext, fprev);
   }
   if (keystring[0] == '\0') //Only was one keyword, no need to start looping through the keywords
   {
      if (!hindex)
      {
         for (hindex = first_hindex; hindex; hindex = hindex->next)
         {
            if (!str_cmp(hindex->keyword, keyword))
               break;
         }
         if (!hindex)
         {
            for (findex = first_fhindex; findex; findex = findex->fnext)
            {
               if (!str_cmp(findex->keyword, keyword))
                  break;
            }
            if (!findex)
            {    
               CREATE(hindex, HINDEX_DATA, 1);
               hindex->keyword = STRALLOC(keyword);
               hindex->first_help = NULL;
               hindex->last_help = NULL;
               hindex->first_hindex = NULL;
               hindex->last_hindex = NULL;
            }
            else
               hindex = findex;
            LINK(hindex, first_hindex, last_hindex, next, prev);  
            LINK(hindex, first_fhindex, last_fhindex, fnext, fprev);
         }
      }  
      if (!hindex->first_help)
      {
         CREATE(hipointer, HINDEX_IPOINTER, 1);
         hipointer->pointer = pHelp;
         LINK(hipointer, hindex->first_help, hindex->last_help, next, prev);
         CREATE(hpointer, HINDEX_POINTER, 1);
         hpointer->pointer = hindex;
         LINK(hpointer, pHelp->first_hindex, pHelp->last_hindex, next, prev);
      }
      else
      {
         for (hipointer = hindex->first_help; hipointer; hipointer = hipointer->next)
         {
            help = hipointer->pointer;
            if (!str_cmp(pHelp->keyword, help->keyword)) // Same helpfile
               break;
         }
         if (!hipointer)
         {
            CREATE(hipointer, HINDEX_IPOINTER, 1);
            hipointer->pointer = pHelp;
            LINK(hipointer, hindex->first_help, hindex->last_help, next, prev);
            CREATE(hpointer, HINDEX_POINTER, 1);
            hpointer->pointer = hindex;
            LINK(hpointer, pHelp->first_hindex, pHelp->last_hindex, next, prev);
         }
      } 
      if (argument)
         return 1;
      //another round...
      value = parse_helpfile_index(fp, pHelp, NULL);
         return value; //once it reaches a value it will loop back out and return that value
   }
   //Will never reach this loop unless there are more than 1 keyword.....
   for (hindex = first_hindex; hindex; hindex = hindex->next)
   {
      if (!hindex->next && str_cmp(keyword, hindex->keyword)) //don't want to break out of this loop just yet...
      {
         for (findex = first_fhindex; findex; findex = findex->fnext)
         {
            if (!str_cmp(findex->keyword, keyword))
               break;
         }
         if (!findex)
         {
            CREATE(hindex2, HINDEX_DATA, 1);
            hindex2->keyword = STRALLOC(keyword);
            hindex2->first_help = NULL;
            hindex2->last_help = NULL;
            hindex2->first_hindex = NULL;
            hindex2->last_hindex = NULL;
            hindex2->first_top_hindex = NULL;
            hindex2->last_top_hindex = NULL;
         }
         else
            hindex2 = findex;
         LINK(hindex2, first_hindex, last_hindex, next, prev);
         LINK(hindex2, first_fhindex, last_fhindex, fnext, fprev);
         hindex = hindex2;
      }  
      if (!str_cmp(keyword, hindex->keyword))
      {             
         for (;;)
         {
            keystring = one_argument(keystring, keyword);
            if (keyword[0] == '\0')
            {
               if (!hindex->first_help)
               {
                  CREATE(hipointer, HINDEX_IPOINTER, 1);
                  hipointer->pointer = pHelp;
                  LINK(hipointer, hindex->first_help, hindex->last_help, next, prev);
                  CREATE(hpointer, HINDEX_POINTER, 1);
                  hpointer->pointer = hindex;
                  LINK(hpointer, pHelp->first_hindex, pHelp->last_hindex, next, prev);
               }
               else
               {
                  for (hipointer = hindex->first_help; hipointer; hipointer = hipointer->next)
                  {
                     help = hipointer->pointer;
                     if (!str_cmp(pHelp->keyword, help->keyword)) // Same helpfile
                     {
                        break;
                     }
                  }
                  if (!hipointer)
                  {
                     CREATE(hipointer, HINDEX_IPOINTER, 1);
                     hipointer->pointer = pHelp;
                     LINK(hipointer, hindex->first_help, hindex->last_help, next, prev);
                     CREATE(hpointer, HINDEX_POINTER, 1);
                     hpointer->pointer = hindex;
                     LINK(hpointer, pHelp->first_hindex, pHelp->last_hindex, next, prev);
                  }
               }       
               break;
            }   
            if (!hindex->first_hindex)
            {
               for (findex = first_fhindex; findex; findex = findex->fnext)
               {
                  if (!str_cmp(findex->keyword, keyword))
                     break;
               }
               if (!findex)
               {
                  CREATE(hindex2, HINDEX_DATA, 1);
                  hindex2->keyword = STRALLOC(keyword);
                  hindex2->first_help = NULL;
                  hindex2->last_help = NULL;
                  hindex2->first_hindex = NULL;
                  hindex2->last_hindex = NULL;
                  hindex2->first_top_hindex = NULL;
                  hindex2->last_top_hindex = NULL;
               }
               else
                  hindex2 = findex;
               LINK(hindex2, hindex->first_hindex, hindex->last_hindex, next, prev);
               LINK(hindex, hindex2->first_top_hindex, hindex2->last_top_hindex, tnext, tprev);
               LINK(hindex2, first_fhindex, last_fhindex, fnext, fprev);
            }
            for (hindex2 = hindex->first_hindex; hindex2; hindex2 = hindex2->next)
            {
               if (!str_cmp(keyword, hindex2->keyword))
                  break;
            }
            if (!hindex2)
            {
               for (findex = first_fhindex; findex; findex = findex->fnext)
               {
                  if (!str_cmp(findex->keyword, keyword))
                     break;
               }
               if (!findex)
               {
                  CREATE(hindex2, HINDEX_DATA, 1);
                  hindex2->keyword = STRALLOC(keyword);
                  hindex2->first_help = NULL;
                  hindex2->last_help = NULL;
                  hindex2->first_hindex = NULL;
                  hindex2->last_hindex = NULL;
                  hindex2->first_top_hindex = NULL;
                  hindex2->last_top_hindex = NULL;
               }
               else
                  hindex2 = findex;
               LINK(hindex2, hindex->first_hindex, hindex->last_hindex, next, prev);
               LINK(hindex, hindex2->first_top_hindex, hindex2->last_top_hindex, tnext, tprev);
               LINK(hindex2, first_fhindex, last_fhindex, fnext, fprev);
            }
            hindex = hindex2; //So this can go in an infinite loop theoretically
         }
         break;  
      } 
   }
   //another round...
   if (argument)
      return 1;
   value = parse_helpfile_index(fp, pHelp, NULL);
      return value; //once it reaches a value it will loop back out and return that value
}
/*
 * Load a help section.
 */
void load_helps(AREA_DATA * tarea, FILE * fp)
{
   HELP_DATA *pHelp;

   for (;;)
   {
      CREATE(pHelp, HELP_DATA, 1);
      pHelp->first_hindex = NULL;
      pHelp->last_hindex = NULL;
      pHelp->level = fread_number(fp);
      pHelp->keyword = fread_string(fp);
      pHelp->first_iname = NULL;
      pHelp->last_hindex = NULL;
      if (pHelp->keyword[0] == '$')
      {
         STRFREE(pHelp->keyword);
         DISPOSE(pHelp);
         break;
      }
      //Parses and creates the helpfile index
      if (parse_helpfile_index(fp, pHelp, NULL) == 1) 
      {
         bug("%s has no hindex, exiting!!!!!", pHelp->keyword);
         STRFREE(pHelp->keyword);
         DISPOSE(pHelp);
         exit(0);
      }
      pHelp->text = fread_string(fp);
      if (pHelp->keyword[0] == '\0')
      {
         STRFREE(pHelp->text);
         STRFREE(pHelp->keyword);
         DISPOSE(pHelp);
         continue;
      }

      if (!str_cmp(pHelp->keyword, "greeting"))
         help_greeting = pHelp->text;
      add_help(pHelp);
   }
   return;
}

*********************
****File 5: Mud.h****
*********************

Find these near the top

  typedef struct descriptor_data DESCRIPTOR_DATA;
  typedef struct exit_data EXIT_DATA;
  typedef struct extra_descr_data EXTRA_DESCR_DATA;
  
Directly below it add this

  typedef struct help_index_data HINDEX_DATA;
  typedef struct help_data_pointer HINDEX_POINTER;
  typedef struct help_index_pointer HINDEX_IPOINTER;
  typedef struct help_index_name HINDEX_NAME;
  
Find This

  MAX_LAYERS
  
Above it add

  #define HINDEX_GENERAL_NAME "General"
  //Uncomment this below to turn on MXP support for hindex code
  //#define HINDEX_MXP 
  
Note uncomment the HINDEX_MXP (remove the //) if you plan on using MXP and installed it back in comm.c.

Find this structure down some

   struct help_data
   
Replace the structure with these structures

/*
 * Help Index Table
 */
struct help_index_data
{
   char *keyword;
   HINDEX_DATA *next; //Next index
   HINDEX_DATA *prev; //Prev index
   HINDEX_DATA *fnext; //next flat index
   HINDEX_DATA *fprev; //prev flat index
   HINDEX_DATA *tnext; //Next index at the top level
   HINDEX_DATA *tprev; //Prev index at the top level
   HINDEX_DATA *first_hindex; //First index below this one
   HINDEX_DATA *last_hindex; //Last index below this one
   HINDEX_DATA *first_top_hindex; //First index above this one
   HINDEX_DATA *last_top_hindex; //Last index below this one
   HINDEX_IPOINTER *first_help;  //First helpfile in this index
   HINDEX_IPOINTER *last_help;  //Last helpfile in this index
};

//Points back to help index data since I need to store this data on every helpfile....
struct help_data_pointer
{
   HINDEX_POINTER *next;
   HINDEX_POINTER *prev;
   HINDEX_DATA *pointer;
};

//Points back to the help data since I need to store this data on every index....
struct help_index_pointer
{
   HINDEX_IPOINTER *next;
   HINDEX_IPOINTER *prev;
   HELP_DATA *pointer;
};

//Used to store the actual groups on a helpfile since it is really hard to track them back...
struct help_index_name
{
    HINDEX_NAME *next;
    HINDEX_NAME *prev;
    char *name;
};

/*
 * Help table types.
 */
struct help_data
{
   HELP_DATA *next;
   HELP_DATA *prev;
   HINDEX_POINTER *first_hindex; //First index structure helpfile is in
   HINDEX_POINTER *last_hindex; //Last index structure helpfile is in
   sh_int level;
   char *keyword;
   HINDEX_NAME *first_iname;
   HINDEX_NAME *last_iname;
   char *text;
};

Find the following PLR FLAG

   PLR_LITTERBUG
   
At the end of that list, add this (make sure it is before the } player_flags; and there is a comma
added after the item right before it)

   PLR_NOSIMILIAR

Find #define INSERT

Above it add the following

//Shifts a link down one spot...       
#define SHIFT_DOWN(slink, olink, last)                                  \
do                                                                      \
{                                                                       \
   if ( (last) == (olink) )                                             \
      (last) = (slink);                                                 \
                                                                        \
    (olink)->prev = (slink)->prev;                                      \
    if ((olink)->prev)                                                  \
       (olink)->prev->next = (olink);                                   \
    (slink)->next = (olink)->next;                                      \
    if ((slink)->next)                                                  \
       (slink)->next->prev = (slink);                                   \
                                                                        \
    (olink)->next = (slink);                                            \
    (slink)->prev = (olink);                                            \
} while(0)      
             
//Shifts a link up one spot... 
#define SHIFT_UP(slink, olink, first)                                   \
do                                                                      \
{                                                                       \
   if ((first) == (olink))                                              \
      (first) = (slink);                                                \
                                                                        \
    (slink)->prev = (olink)->prev;                                      \
    if ((slink)->prev)                                                  \
       (slink)->prev->next = (slink);                                   \
    (olink)->next = (slink)->next;                                      \
    if ((olink)->next)                                                  \
       (olink)->next->prev = (olink);                                   \
                                                                        \
    (slink)->next = (olink);                                            \
    (olink)->prev = (slink);                                            \
} while(0)

Find the following down below

  extern HELP_DATA *first_help;
  extern HELP_DATA *last_help;
  
Add the following below those two lines

  extern HINDEX_DATA *first_hindex;
  extern HINDEX_DATA *last_hindex;
  extern HINDEX_DATA *first_fhindex; //Flat help index
  extern HINDEX_DATA *last_fhindex; //Flag help index
  
Find this comment down below

   /* db.c */
   
In the db.c function declaration list, add this

   int parse_helpfile_index args((FILE *fp, HELP_DATA *pHelp, char *argument));
   

****************Step 3 - Compile and Setup****************

Once you are done with that, you need to add do_hindex into mud.h and tables.c.
After that, do a make clean (note a make clean not a make) and hope to god it
compiles fine!  Once it does, you are ready to reboot/copyover your mud.  Once
you do that, create the hedit command

cedit hedit create do_hedit
cedit hedit level 1
cedit save cmdtable

If you type hindex map now, you will notice you have only the General group.  Also,
you will notice if you do a help on any file in that group, you will get booted.  This
is because it is trying to show thousands of helpfiles and I don't have this setup to
run on pager.  So, you need to seperate the helpfiles out.  This file is getting long
enough, so I am going to break it up into a few more.  Just read these files to get
more information

hindexhelpediting.txt - Instructions on how to alter helpfiles offline and online.
hindex.help - Help files to add for hindex :-)
hindextweeks.txt - Small changes you can add so you can have the code in while you alter
                   files online/offline