diff -u -N stk/Makefile src/Makefile
--- stk/Makefile	Mon Oct 27 22:35:46 1997
+++ src/Makefile	Mon Oct 27 19:50:09 1997
@@ -22,8 +22,9 @@
 	castle.o class.o config.o constants.o db.o fight.o graph.o handler.o \
 	house.o interpreter.o limits.o magic.o mail.o mobact.o modify.o \
 	objsave.o olc.o shop.o spec_assign.o spec_procs.o spell_parser.o \
-	spells.o utils.o weather.o redit.o oedit.o zedit.o medit.o sedit.o
-
+	spells.o utils.o weather.o hedit.c redit.o oedit.o zedit.o medit.o \
+	sedit.o
+  
 default: .accepted
 	$(MAKE) ../bin/circle
 
@@ -219,3 +220,6 @@
 	$(CC) -c $(CFLAGS) medit.c 
 sedit.o: sedit.c conf.h sysdep.h structs.h utils.h comm.h db.h olc.h shop.h
 	$(CC) -c $(CFLAGS) sedit.c 
+hedit.o: hedit.c conf.h sysdep.h structs.h interpreter.h comm.h utils.h db.h \
+  olc.h
+	$(CC) -c $(CFLAGS) hedit.c
diff -u -N stk/db.c src/db.c
--- stk/db.c	Mon Oct 27 19:41:46 1997
+++ src/db.c	Mon Oct 27 21:06:14 1997
@@ -1297,6 +1297,12 @@
       get_one_line(fl, line);
     }
 
+    el.min_level = 0;
+    if ((*line == '#') && (*(line + 1) != 0))
+      el.min_level = atoi((line + 1));
+
+    el.min_level = MAX(0, MIN(el.min_level, LVL_IMPL));
+
     /* now, add the entry to the index with each keyword on the keyword line */
     el.duplicate = 0;
     el.entry = str_dup(entry);
diff -u -N stk/db.h src/db.h
--- stk/db.h	Mon Oct 27 19:41:45 1997
+++ src/db.h	Mon Oct 27 22:12:40 1997
@@ -37,6 +37,7 @@
 #define BACKGROUND_FILE	"text/background" /* for the background story	*/
 #define POLICIES_FILE	"text/policies"	/* player policies/rules	*/
 #define HANDBOOK_FILE	"text/handbook"	/* handbook for new immorts	*/
+#define HELP_FILE	"text/help/help.hlp" /* unified help file */
 
 #define IDEA_FILE	"misc/ideas"	/* for the 'idea'-command	*/
 #define TYPO_FILE	"misc/typos"	/*         'typo'		*/
@@ -153,6 +154,7 @@
 struct help_index_element {
    char	*keyword;
    char *entry;
+   int min_level;
    int duplicate;
 };
 
diff -u -N stk/hedit.c src/hedit.c
--- stk/hedit.c	Wed Dec 31 19:00:00 1969
+++ src/hedit.c	Mon Oct 27 19:42:24 1997
@@ -0,0 +1,371 @@
+/*
+ * File: hedit.c
+ * Comment: OLC for MUDs -- this one edits help files
+ * By Steve Wolfe
+ * for use with OasisOLC
+ */
+
+#include "conf.h"
+#include "sysdep.h"
+
+#include "structs.h"
+#include "interpreter.h"
+#include "handler.h"
+#include "comm.h"
+#include "utils.h"
+#include "db.h"
+#include "olc.h"
+#include "screen.h"
+
+extern int top_of_helpt;
+extern struct help_index_element *help_table;
+int find_help(char *keyword);
+
+void free_help(struct help_index_element *help);
+
+/* function protos */
+void hedit_disp_menu(struct descriptor_data *d);
+void hedit_parse(struct descriptor_data *d, char *arg);
+void hedit_setup_new(struct descriptor_data *d);
+void hedit_setup_existing(struct descriptor_data *d, int real_num);
+void hedit_save_to_disk(struct descriptor_data *d);
+void hedit_save_internally(struct descriptor_data *d);
+void index_boot(int mode);
+
+/*
+ * Utils and exported functions.
+ */
+
+void hedit_setup_new(struct descriptor_data *d)
+{
+  CREATE(OLC_HELP(d), struct help_index_element, 1);
+  OLC_HELP(d)->keyword = str_dup(OLC_STORAGE(d));
+  OLC_HELP(d)->entry = str_dup("This help file is unfinished.\r\n");
+  OLC_HELP(d)->min_level = 0;
+  OLC_HELP(d)->duplicate = 0;
+  hedit_disp_menu(d);
+  OLC_VAL(d) = 0;
+}
+
+/*------------------------------------------------------------------------*/
+
+void hedit_setup_existing(struct descriptor_data *d, int real_num)
+{
+  CREATE(OLC_HELP(d), struct help_index_element, 1);
+  OLC_HELP(d)->keyword = str_dup(help_table[real_num].keyword);
+  OLC_HELP(d)->entry = str_dup(help_table[real_num].entry);
+  OLC_HELP(d)->min_level = help_table[real_num].min_level;
+  OLC_HELP(d)->duplicate = help_table[real_num].duplicate;
+  OLC_VAL(d) = 0;
+  hedit_disp_menu(d);
+}
+
+
+void hedit_save_internally(struct descriptor_data *d)
+{
+  struct help_index_element *new_help_table = NULL;
+  int i;
+
+  /* add a new help element into the list */
+  if (OLC_ZNUM(d) > top_of_helpt) {
+    CREATE(new_help_table, struct help_index_element, top_of_helpt + 2);
+    for (i = 0; i <= top_of_helpt; i++)
+      new_help_table[i] = help_table[i];
+    new_help_table[++top_of_helpt] = *OLC_HELP(d);
+    free(help_table);
+    help_table = new_help_table;
+  } else {
+    i = find_help(OLC_HELP(d)->keyword);
+
+    free_help(help_table + OLC_ZNUM(d));
+    help_table[OLC_ZNUM(d)] = *OLC_HELP(d);
+  }
+  olc_add_to_save_list(HEDIT_PERMISSION, OLC_SAVE_HELP);
+}
+
+
+/*------------------------------------------------------------------------*/
+
+void hedit_save_to_disk(struct descriptor_data *d)
+{
+  FILE *fp;
+  int i;
+
+  if (!(fp = fopen(HELP_FILE, "w+"))) {
+    sprintf(buf, "Can't open help file '%s'", HELP_FILE);
+    perror(buf);
+    exit(1);
+  }
+  for (i = 0; i <= top_of_helpt; i++) {
+    if (help_table[i].duplicate > 0)
+      continue;
+
+    /*. Remove the '\r\n' sequences from entry . */
+    strcpy(buf1, help_table[i].entry ? help_table[i].entry : "Empty");
+    strip_string(buf1);
+
+    sprintf(buf, "%s#%d\n",
+	    buf1,
+	    help_table[i].min_level);
+    fputs(buf, fp);
+  }
+
+  fprintf(fp, "$\n");
+  fclose(fp);
+  olc_remove_from_save_list(HEDIT_PERMISSION, OLC_SAVE_HELP);
+}
+
+/*------------------------------------------------------------------------*/
+
+/* Menu functions */
+
+/* the main menu */
+void hedit_disp_menu(struct descriptor_data *d)
+{
+  struct help_index_element *help;
+  char *nrm = CCNRM(d->character, C_NRM);
+  char *yel = CCYEL(d->character, C_NRM);
+  char *grn = CCGRN(d->character, C_NRM);
+
+  help = OLC_HELP(d);
+
+  sprintf(buf,
+	  "[H[J"
+	  "%s1%s) Keywords    : %s%s\r\n"
+	  "%s2%s) Entry       :\r\n%s%s"
+	  "%s3%s) Min Level   : %s%d\r\n"
+	  "%sQ%s) Quit\r\n"
+	  "Enter choice : ",
+
+	  grn, nrm, yel, help->keyword,
+	  grn, nrm, yel, help->entry,
+	  grn, nrm, yel, help->min_level,
+	  grn, nrm
+      );
+  send_to_char(buf, d->character);
+
+  OLC_MODE(d) = HEDIT_MAIN_MENU;
+}
+
+/*
+ * The main loop
+ */
+
+void hedit_parse(struct descriptor_data *d, char *arg)
+{
+  int i;
+
+  switch (OLC_MODE(d)) {
+  case HEDIT_CONFIRM_SAVESTRING:
+    switch (*arg) {
+    case 'y':
+    case 'Y':
+      hedit_save_internally(d);
+      hedit_save_to_disk(d);
+      if (help_table) {
+	for (i = 0; i <= top_of_helpt; i++) {
+	  if (help_table[i].keyword)
+	    free(help_table[i].keyword);
+	  if (help_table[i].entry && !help_table[i].duplicate)
+	    free(help_table[i].entry);
+	}
+	free(help_table);
+      }
+      top_of_helpt = 0;
+      index_boot(DB_BOOT_HLP);
+
+
+      sprintf(buf, "OLC: %s edits help.", GET_NAME(d->character));
+      mudlog(buf, CMP, LVL_IMPL, TRUE);
+      /* do not free the strings.. just the structure */
+      cleanup_olc(d, CLEANUP_STRUCTS);
+      send_to_char("Help saved to memory.\r\n", d->character);
+      break;
+    case 'n':
+    case 'N':
+      /* free everything up, including strings etc */
+      cleanup_olc(d, CLEANUP_ALL);
+      break;
+    default:
+      send_to_char("Invalid choice!\r\nDo you wish to save this help internally? ", d->character);
+      break;
+    }
+    return;			/* end of HEDIT_CONFIRM_SAVESTRING */
+
+  case HEDIT_CONFIRM_EDIT:
+    switch (*arg) {
+    case 'y':
+    case 'Y':
+      hedit_setup_existing(d, OLC_ZNUM(d));
+      break;
+    case 'q':
+    case 'Q':
+      cleanup_olc(d, CLEANUP_ALL);
+      break;
+    case 'n':
+    case 'N':
+      OLC_ZNUM(d)++;
+      for (; (OLC_ZNUM(d) <= top_of_helpt); OLC_ZNUM(d)++)
+	if (is_abbrev(OLC_STORAGE(d), help_table[OLC_ZNUM(d)].keyword))
+	  break;
+      if (OLC_ZNUM(d) > top_of_helpt) {
+	if (find_help(OLC_STORAGE(d)) > NOTHING) {
+	  cleanup_olc(d, CLEANUP_ALL);
+	  break;
+	}
+	sprintf(buf, "Do you wish to add help on '%s'? ",
+		OLC_STORAGE(d));
+	send_to_char(buf, d->character);
+	OLC_MODE(d) = HEDIT_CONFIRM_ADD;
+      } else {
+	sprintf(buf, "Do you wish to edit help on '%s'? ", help_table[OLC_ZNUM(d)].keyword);
+	send_to_char(buf, d->character);
+	OLC_MODE(d) = HEDIT_CONFIRM_EDIT;
+      }
+      break;
+    default:
+      sprintf(buf, "Invalid choice!\r\nDo you wish to edit help on '%s'? ", help_table[OLC_ZNUM(d)].keyword);
+      send_to_char(buf, d->character);
+      break;
+    }
+    return;
+
+  case HEDIT_CONFIRM_ADD:
+    switch (*arg) {
+    case 'y':
+    case 'Y':
+      hedit_setup_new(d);
+      break;
+    case 'n':
+    case 'N':
+    case 'q':
+    case 'Q':
+      cleanup_olc(d, CLEANUP_ALL);
+      break;
+    default:
+      sprintf(buf, "Invalid choice!\r\nDo you wish to add help on '%s'? ", OLC_STORAGE(d));
+      send_to_char(buf, d->character);
+      break;
+    }
+    return;
+
+  case HEDIT_MAIN_MENU:
+    switch (*arg) {
+    case 'q':
+    case 'Q':
+      if (OLC_VAL(d)) {		/* Something was modified */
+	send_to_char("Do you wish to save this help internally? ", d->character);
+	OLC_MODE(d) = HEDIT_CONFIRM_SAVESTRING;
+      } else
+	cleanup_olc(d, CLEANUP_ALL);
+      break;
+    case '1':
+      send_to_char("Enter all of the keywords for this help entry: ", d->character);
+      OLC_MODE(d) = HEDIT_KEYWORD;
+      return;
+    case '2':
+      OLC_MODE(d) = HEDIT_ENTRY;
+      SEND_TO_Q("\x1B[H\x1B[J", d);
+      SEND_TO_Q("Enter the help info: (/s saves /h for help)\r\n\r\n", d);
+      d->backstr = NULL;
+      if (OLC_HELP(d)->entry) {
+	SEND_TO_Q(OLC_HELP(d)->entry, d);
+	d->backstr = str_dup(OLC_HELP(d)->entry);
+      }
+      d->str = &OLC_HELP(d)->entry;
+      d->max_str = MAX_STRING_LENGTH;
+      d->mail_to = 0;
+      OLC_VAL(d) = 1;
+      break;
+    case '3':
+      send_to_char("Enter the minimum level a player has to be to read this help: "
+		   ,d->character);
+      OLC_MODE(d) = HEDIT_MIN_LEVEL;
+      return;
+    default:
+      hedit_disp_menu(d);
+      break;
+    }
+    return;
+
+  case HEDIT_KEYWORD:
+    if (*arg) {
+      if (strchr(arg, ' ')) {
+	hedit_disp_menu(d);
+	return;
+      } else {
+	if (OLC_HELP(d)->keyword)
+	  free(OLC_HELP(d)->keyword);
+	OLC_HELP(d)->keyword = str_dup(arg);
+      }
+    } else {
+      hedit_disp_menu(d);
+      return;
+    }
+    break;
+
+  case HEDIT_ENTRY:
+    /* should never get here */
+    mudlog("SYSERR: Reached HEDIT_ENTRY in hedit_parse", BRF, LVL_BUILDER, TRUE);
+    break;
+  case HEDIT_MIN_LEVEL:
+    if (*arg) {
+      i = atoi(arg);
+      if ((i < 0) && (i > LVL_IMPL)) {
+	hedit_disp_menu(d);
+	return;
+      } else
+	OLC_HELP(d)->min_level = i;
+    } else {
+      hedit_disp_menu(d);
+      return;
+    }
+    break;
+  default:
+    /* we should never get here */
+    break;
+  }
+  OLC_VAL(d) = 1;
+  hedit_disp_menu(d);
+}
+
+int find_help(char *keyword)
+{
+
+  extern int top_of_helpt;
+  extern struct help_index_element *help_table;
+
+  int chk, bot, top, mid, minlen;
+
+  bot = 0;
+  top = top_of_helpt;
+  minlen = strlen(keyword);
+
+  for (;;) {
+    mid = (bot + top) / 2;
+
+    if (bot > top)
+      return -1;
+    else if (!(chk = strn_cmp(keyword, help_table[mid].keyword, minlen))) {
+      /* trace backwards to find first matching entry. Thanks Jeff Fink! */
+      while ((mid > 0) &&
+       (!(chk = strn_cmp(keyword, help_table[mid - 1].keyword, minlen))))
+	mid--;
+      return mid;
+    } else {
+      if (chk > 0)
+	bot = mid + 1;
+      else
+	top = mid - 1;
+    }
+  }
+}
+
+void free_help(struct help_index_element *help)
+{
+  if (help->keyword)
+    free(help->keyword);
+  if (help->entry)
+    free(help->entry);
+  memset(help, 0, sizeof(struct help_index_element));
+}
diff -u -N stk/interpreter.c src/interpreter.c
--- stk/interpreter.c	Mon Oct 27 22:35:47 1997
+++ src/interpreter.c	Mon Oct 27 20:13:14 1997
@@ -56,7 +56,7 @@
 void zedit_parse(struct descriptor_data *d, char *arg);
 void medit_parse(struct descriptor_data *d, char *arg);
 void sedit_parse(struct descriptor_data *d, char *arg);
-
+void hedit_parse(struct descriptor_data *d, char *arg);
 
 /* prototypes for all do_x functions. */
 ACMD(do_action);
@@ -315,6 +315,7 @@
   { "gtell"    , POS_SLEEPING, do_gsay     , 0, 0 },
 
   { "help"     , POS_DEAD    , do_help     , 0, 0 },
+  { "hedit"    , POS_DEAD    , do_olc      , LVL_BUILDER, SCMD_OLC_HEDIT },
   { "handbook" , POS_DEAD    , do_gen_ps   , LVL_IMMORT, SCMD_HANDBOOK },
   { "hcontrol" , POS_DEAD    , do_hcontrol , LVL_GRGOD, 0 },
   { "hiccup"   , POS_RESTING , do_action   , 0, 0 },
@@ -1282,6 +1283,9 @@
     break;
   case CON_SEDIT: 
     sedit_parse(d, arg);
+    break;
+  case CON_HEDIT: 
+    hedit_parse(d, arg);
     break;
   /*. End of OLC states .*/
 
diff -u -N stk/interpreter.h src/interpreter.h
--- stk/interpreter.h	Mon Oct 27 22:35:48 1997
+++ src/interpreter.h	Mon Oct 27 21:27:26 1997
@@ -206,4 +206,4 @@
 #define SCMD_OLC_MEDIT  3
 #define SCMD_OLC_SEDIT  4
 #define SCMD_OLC_SAVEINFO  5
-
+#define SCMD_OLC_HEDIT  6
diff -u -N stk/modify.c src/modify.c
--- stk/modify.c	Mon Oct 27 22:35:48 1997
+++ src/modify.c	Mon Oct 27 20:25:16 1997
@@ -578,12 +578,14 @@
     extern void redit_disp_extradesc_menu(struct descriptor_data *d);
     extern void redit_disp_exit_menu(struct descriptor_data *d);
     extern void medit_disp_menu(struct descriptor_data *d);
+    extern void hedit_disp_menu(struct descriptor_data *d);
      
      /* here we check for the abort option and reset the pointers */
      if ((terminator == 2) &&
 	 ((STATE(d) == CON_REDIT) ||
 	  (STATE(d) == CON_MEDIT) ||
 	  (STATE(d) == CON_OEDIT) ||
+	  (STATE(d) == CON_HEDIT) ||
 	  (STATE(d) == CON_EXDESC))) {
 	free(*d->str);
 	if (d->backstr) {
@@ -624,7 +626,8 @@
 	   redit_disp_extradesc_menu(d);
 	   break;
       }
-     }
+     } else if (STATE(d) == CON_HEDIT)
+       hedit_disp_menu(d);
      else if (!d->connected && (PLR_FLAGGED(d->character, PLR_MAILING))) {
 	if ((terminator == 1) && *d->str) {
       store_mail(d->mail_to, GET_IDNUM(d->character), *d->str);
diff -u -N stk/olc.c src/olc.c
--- stk/olc.c	Mon Nov 18 08:55:35 1996
+++ src/olc.c	Mon Oct 27 22:02:24 1997
@@ -25,6 +25,8 @@
 extern int top_of_zone_table;
 extern struct zone_data *zone_table;
 extern struct descriptor_data *descriptor_list;
+extern struct help_index_element *help_table;
+extern int top_of_helpt;
 
 /*. External functions .*/
 extern zedit_setup(struct descriptor_data *d, int room_num);
@@ -46,6 +48,9 @@
 extern free_shop(struct shop_data *shop);
 extern free_room(struct room_data *room);
 extern void medit_free_mobile(struct char_data * mob);
+extern hedit_save_to_disk(struct descriptor_data *d);
+extern void free_help(struct help_index_element *help);
+extern int find_help(char *keyword);
 
 /*. Internal function prototypes .*/
 int real_zone(int number);
@@ -58,12 +63,13 @@
   int con_type;
 };
 
-struct olc_scmd_data olc_scmd_info[5] =
+struct olc_scmd_data olc_scmd_info[6] =
 { {"room", 	CON_REDIT},
   {"object", 	CON_OEDIT},
   {"room",	CON_ZEDIT},
   {"mobile", 	CON_MEDIT},
-  {"shop", 	CON_SEDIT}
+  {"shop", 	CON_SEDIT},
+  {"help", 	CON_HEDIT}
 };
 
 /*------------------------------------------------------------*\
@@ -102,18 +108,26 @@
         sprintf(buf, "Specify a %s VNUM to edit.\r\n", olc_scmd_info[subcmd].text);
         send_to_char (buf, ch);
         return;
+      case SCMD_OLC_HEDIT:
+        send_to_char("Specify a help topic to edit.\r\n", ch);
+        return;
     }
   } else if (!isdigit (*buf1))
   {
     if (strncmp("save", buf1, 4) == 0)
-    { if (!*buf2)
+    { if (subcmd == SCMD_OLC_HEDIT) {
+        save = 1;
+        number = 0;
+      } else if (!*buf2)
       { send_to_char("Save which zone?\r\n", ch);
         return;
       } else 
       { save = 1;
         number = atoi(buf2) * 100;
       }
-    } else if (subcmd == SCMD_OLC_ZEDIT && GET_LEVEL(ch) >= LVL_IMPL)
+    } else if (subcmd == SCMD_OLC_HEDIT)
+      number = 0;
+    else if (subcmd == SCMD_OLC_ZEDIT && GET_LEVEL(ch) >= LVL_IMPL)
     { if ((strncmp("new", buf1, 3) == 0) && *buf2)
         zedit_new_zone(ch, atoi(buf2));
       else
@@ -126,14 +140,18 @@
   }
 
   /*. If a numeric argument was given, get it .*/
-  if (number == -1)
+  if ((number == -1) && (subcmd != SCMD_OLC_HEDIT))
     number = atoi(buf1);
 
   /*. Check whatever it is isn't already being edited .*/
   for (d = descriptor_list; d; d = d->next)
     if (d->connected == olc_scmd_info[subcmd].con_type)
-      if (d->olc && OLC_NUM(d) == number)
-      { sprintf(buf, "That %s is currently being edited by %s.\r\n",
+      if (d->olc && OLC_NUM(d) == number && number != NOTHING)
+      { if (subcmd == SCMD_OLC_HEDIT)
+          sprintf(buf, "Help files are currently being edited by %s\r\n", 
+	    (CAN_SEE(ch, d->character) ? GET_NAME(d->character) : "someone"));
+        else 
+	sprintf(buf, "That %s is currently being edited by %s.\r\n",
                 olc_scmd_info[subcmd].text, GET_NAME(d->character));
         send_to_char(buf, ch);
         return;
@@ -144,22 +162,30 @@
   /*. Give descriptor an OLC struct .*/
   CREATE(d->olc, struct olc_data, 1);
 
-  /*. Find the zone .*/
-  OLC_ZNUM(d) = real_zone(number);
-  if (OLC_ZNUM(d) == -1)
-  { send_to_char ("Sorry, there is no zone for that number!\r\n", ch); 
-    free(d->olc);
-    return;
-  }
+  if (subcmd != SCMD_OLC_HEDIT) {
+    /*. Find the zone .*/
+    OLC_ZNUM(d) = real_zone(number);
+    if (OLC_ZNUM(d) == -1) { 
+      send_to_char ("Sorry, there is no zone for that number!\r\n", ch); 
+      free(d->olc);
+      return;
+    }
 
-  /*. Everyone but IMPLs can only edit zones they have been assigned .*/
-  if ((GET_LEVEL(ch) < LVL_IMPL) && 
-      (zone_table[OLC_ZNUM(d)].number != GET_OLC_ZONE(ch)))
-  { send_to_char("You do not have permission to edit this zone.\r\n", ch); 
+    /*. Everyone but IMPLs can only edit zones they have been assigned .*/
+    if ((GET_LEVEL(ch) < LVL_IMPL) && 
+      (zone_table[OLC_ZNUM(d)].number != GET_OLC_ZONE(ch))) { 
+      send_to_char("You do not have permission to edit this zone.\r\n", ch); 
+      free(d->olc);
+      return;
+    }
+  } else if ((!(GET_LEVEL(ch) < LVL_BUILDER)) &&
+             (!ch->player_specials->saved.olc_zone == HEDIT_PERMISSION)) {
+    send_to_char("You do not have permission to edit help files.\r\n", ch);
     free(d->olc);
     return;
   }
  
+
   if(save)
   { switch(subcmd)
     { case SCMD_OLC_REDIT: 
@@ -197,12 +223,44 @@
         mudlog(buf, CMP, LVL_BUILDER, TRUE);
         sedit_save_to_disk(d); 
         break;
+      case SCMD_OLC_HEDIT:
+        send_to_char("Saving all help files.\r\n", ch);
+        sprintf(buf, "OLC: %s saves help file",
+	      GET_NAME(ch));
+        mudlog(buf, CMP, LVL_BUILDER, TRUE);
+        hedit_save_to_disk(d);
+        break;
     }
     free(d->olc);
     return;
   }
  
-  OLC_NUM(d) = number;
+  if (subcmd != SCMD_OLC_HEDIT)
+    OLC_NUM(d) = number;
+  else {
+    OLC_NUM(d) = 0;
+    OLC_STORAGE(d) = str_dup(buf1);
+    for (OLC_ZNUM(d) = 0; (OLC_ZNUM(d) <= top_of_helpt); OLC_ZNUM(d)++) {
+      if (is_abbrev(OLC_STORAGE(d), help_table[OLC_ZNUM(d)].keyword))
+	break;
+    }
+    if (OLC_ZNUM(d) > top_of_helpt) {
+      if (find_help(OLC_STORAGE(d)) > NOTHING) {
+	cleanup_olc(d, CLEANUP_ALL);
+	send_to_char("That help topic already exists.\r\n", ch);
+	return;
+      }
+      sprintf(buf, "Do you wish to add a help topic on '%s'? ", OLC_STORAGE(d));
+      send_to_char(buf, ch);
+      OLC_MODE(d) = HEDIT_CONFIRM_ADD;
+    } else {
+      sprintf(buf, "Do you wish to edit the help topic on '%s'? ",
+	      help_table[OLC_ZNUM(d)].keyword);
+      send_to_char(buf, ch);
+      OLC_MODE(d) = HEDIT_CONFIRM_EDIT;
+    }
+  }
+  
 
   /*. Steal players descriptor start up subcommands .*/
   switch(subcmd)
@@ -247,6 +305,9 @@
       else
         sedit_setup_new(d);
       STATE(d) = CON_SEDIT;
+      break;
+    case SCMD_OLC_HEDIT:
+      STATE(d) = CON_HEDIT;
       break;
   }
   act("$n starts using OLC.", TRUE, d->character, 0, 0, TO_ROOM);
diff -u -N stk/olc.c src/olc.c
--- stk/olc.c	Wed Oct 29 20:25:15 1997
+++ src/olc.c	Wed Oct 29 20:26:04 1997
@@ -413,6 +413,20 @@
       }
     }
 
+    if (OLC_HELP(d)) {
+      switch (cleanup_type) {
+      case CLEANUP_ALL:
+	free_help(OLC_HELP(d));
+	break;
+      case CLEANUP_STRUCTS:
+	free(OLC_HELP(d));
+	break;
+      default:
+	/* Caller has screwed up */
+	break;
+      }
+    }
+
     /*. Restore desciptor playing status .*/
     if (d->character)
     { REMOVE_BIT(PLR_FLAGS(d->character), PLR_WRITING);
diff -u -N stk/olc.h src/olc.h
--- stk/olc.h	Mon Nov 18 08:55:32 1996
+++ src/olc.h	Mon Oct 27 22:11:30 1997
@@ -45,12 +45,14 @@
   int zone_num;
   int number;
   int value;
+  char *storage;
   struct char_data *mob;
   struct room_data *room;
   struct obj_data *obj;
   struct zone_data *zone;
   struct shop_data *shop;
   struct extra_descr_data *desc;
+  struct help_index_element *help;
 };
 
 struct olc_save_info {
@@ -81,6 +83,8 @@
 #define OLC_MOB(d)	((d)->olc->mob)	  	/*. Mob structure	.*/
 #define OLC_SHOP(d) 	((d)->olc->shop)	/*. Shop structure	.*/
 #define OLC_DESC(d) 	((d)->olc->desc)	/*. Extra description	.*/
+#define OLC_STORAGE(d)  ((d)->olc->storage)     /*. For command storage . */
+#define OLC_HELP(d)   ((d)->olc->help)  /*. Help structure    . */
 
 /*. Other macros .*/
 
@@ -97,6 +101,7 @@
 #define OLC_SAVE_ZONE			2
 #define OLC_SAVE_MOB			3
 #define OLC_SAVE_SHOP			4
+#define OLC_SAVE_HELP			5
 
 /* Submodes of OEDIT connectedness */
 #define OEDIT_MAIN_MENU              	1
@@ -233,3 +238,14 @@
 #define MAX_MOB_DESC	512
 #define MAX_OBJ_DESC	512
 
+/* Submodes of HEDIT connectedness      */
+#define HEDIT_CONFIRM_SAVESTRING	0
+#define HEDIT_CONFIRM_EDIT		1
+#define HEDIT_CONFIRM_ADD		2
+#define HEDIT_MAIN_MENU			3
+#define HEDIT_KEYWORD			4
+#define HEDIT_ENTRY			5
+#define HEDIT_MIN_LEVEL			6
+
+/* hedit permission */
+#define HEDIT_PERMISSION		666
diff -u -N stk/structs.h src/structs.h
--- stk/structs.h	Mon Oct 27 22:35:49 1997
+++ src/structs.h	Mon Oct 27 21:28:06 1997
@@ -229,6 +229,7 @@
 #define CON_ZEDIT	 19		/*. OLC mode - zone info edit  .*/
 #define CON_MEDIT	 20		/*. OLC mode - mobile edit     .*/
 #define CON_SEDIT	 21		/*. OLC mode - shop edit       .*/
+#define CON_HEDIT	 22		/*. OLC mode - help edit       .*/
 
 
 /* Character equipment positions: used as index for char_data.equipment[] */
