diff -BbuprN tbamud-3.55/lib/world/qst/index tbamud-3.55+quests/lib/world/qst/index
--- tbamud-3.55/lib/world/qst/index	1970-01-01 00:00:00.000000000 +0000
+++ tbamud-3.55+quests/lib/world/qst/index	2008-01-31 12:53:46.710047000 +0000
@@ -0,0 +1 @@
+$
diff -BbuprN tbamud-3.55/src/Makefile.amiga tbamud-3.55+quests/src/Makefile.amiga
--- tbamud-3.55/src/Makefile.amiga	2008-01-16 23:21:14.000000000 +0000
+++ tbamud-3.55+quests/src/Makefile.amiga	2008-01-31 09:56:06.147547000 +0000
@@ -192,3 +192,12 @@ utils.o: utils.c conf.h sysdep.h structs
 weather.o: weather.c conf.h sysdep.h structs.h utils.h comm.h handler.h \
   interpreter.h db.h
 	$(CC) -c $(CFLAGS) weather.c
+quest.o: quest.c conf.h sysdep.h structs.h utils.h interpreter.h handler.h \
+  comm.h db.h screen.h quest.h
+	$(CC) -c $(CFLAGS) quest.c
+qedit.o: qedit.c conf.h sysdep.h structs.h utils.h comm.h db.h oasis.h \
+  improved-edit.h screen.h genolc.h genzon.h interpreter.h quest.h
+	$(CC) -c $(CFLAGS) qedit.c
+genqst.o: genqst.c conf.h sysdep.h structs.h utils.h db.h quest.h \
+  genolc.h genzon.h 
+	$(CC) -c $(CFLAGS) genqst.c
diff -BbuprN tbamud-3.55/src/Makefile.bcc tbamud-3.55+quests/src/Makefile.bcc
--- tbamud-3.55/src/Makefile.bcc	2008-01-16 23:21:14.000000000 +0000
+++ tbamud-3.55+quests/src/Makefile.bcc	2008-01-31 09:59:18.553797000 +0000
@@ -78,7 +78,10 @@ Dep_circledexe = \
    spec_procs.obj\
    spec_assign.obj\
    utils.obj\
-   weather.obj
+   weather.obj\
+   quest.obj\
+   qedit.obj\
+   genqst.obj
 
 circle.exe : $(Dep_circledexe)
   $(TLINK32) @&&|
@@ -119,7 +122,10 @@ spell_parser.obj+
 spec_procs.obj+
 spec_assign.obj+
 utils.obj+
-weather.obj
+weather.obj+
+quest.obj+
+qedit.obj+
+genqst.obj
 $<,$*
 C:\BC5\LIB\bidsfi.lib+
 C:\BC5\LIB\import32.lib+
@@ -306,6 +312,21 @@ weather.obj :  weather.c
  $(CompOptsAt_circledexe) $(CompInheritOptsAt_circledexe) -o$@ weather.c
 |
 
+quest.obj :  quest.c
+  $(BCC32) -P- -c @&&|
+ $(CompOptsAt_circledexe) $(CompInheritOptsAt_circledexe) -o$@ quest.c
+|
+
+qedit.obj :  qedit.c
+  $(BCC32) -P- -c @&&|
+ $(CompOptsAt_circledexe) $(CompInheritOptsAt_circledexe) -o$@ qedit.c
+|
+
+genqst.obj :  genqst.c
+  $(BCC32) -P- -c @&&|
+ $(CompOptsAt_circledexe) $(CompInheritOptsAt_circledexe) -o$@ genqst.c
+|
+
 # Compiler configuration file
 BccW32.cfg : 
    Copy &&|
diff -BbuprN tbamud-3.55/src/Makefile.bcc55 tbamud-3.55+quests/src/Makefile.bcc55
--- tbamud-3.55/src/Makefile.bcc55	2008-01-16 23:21:14.000000000 +0000
+++ tbamud-3.55+quests/src/Makefile.bcc55	2008-01-31 10:00:37.210047000 +0000
@@ -79,7 +79,10 @@ Dep_circledexe = \
    spec_procs.obj\
    spec_assign.obj\
    utils.obj\
-   weather.obj
+   weather.obj\
+   quest.obj\
+   qedit.obj\
+   genqst.obj
 
 circle.exe : $(Dep_circledexe)
   $(TLINK32) @&&|
@@ -120,7 +123,10 @@ spell_parser.obj+
 spec_procs.obj+
 spec_assign.obj+
 utils.obj+
-weather.obj
+weather.obj+
+quest.obj+
+qedit.obj+
+genqst.obj
 $<,$*
 C:\BORLAND\BCC55\LIB\import32.lib+
 C:\BORLAND\BCC55\LIB\cw32i.lib
@@ -306,6 +312,21 @@ weather.obj :  weather.c
  $(CompOptsAt_circledexe) $(CompInheritOptsAt_circledexe) -o$@ weather.c
 |
 
+quest.obj :  quest.c
+  $(BCC32) -P- -c @&&|
+ $(CompOptsAt_circledexe) $(CompInheritOptsAt_circledexe) -o$@ quest.c
+|
+
+qedit.obj :  qedit.c
+  $(BCC32) -P- -c @&&|
+ $(CompOptsAt_circledexe) $(CompInheritOptsAt_circledexe) -o$@ qedit.c
+|
+
+genqst.obj :  genqst.c
+  $(BCC32) -P- -c @&&|
+ $(CompOptsAt_circledexe) $(CompInheritOptsAt_circledexe) -o$@ genqst.c
+|
+
 # Compiler configuration file
 BccW32.cfg : 
    Copy &&|
diff -BbuprN tbamud-3.55/src/Makefile.in tbamud-3.55+quests/src/Makefile.in
--- tbamud-3.55/src/Makefile.in	2008-01-16 23:21:14.000000000 +0000
+++ tbamud-3.55+quests/src/Makefile.in	2008-01-31 09:49:42.819422000 +0000
@@ -34,7 +34,7 @@ OBJFILES = act.comm.o act.informative.o 
 	mobact.o modify.o oasis.o oasis_copy.o oasis_delete.o oasis_list.o \
 	objsave.o oedit.o players.o random.o redit.o sedit.o shop.o \
 	spec_assign.o spec_procs.o spell_parser.o spells.o tedit.o utils.o \
-	weather.o zedit.o zmalloc.o 
+	weather.o zedit.o zmalloc.o quest.o genqst.o qedit.o 
 
 CXREF_FILES = act.comm.c act.informative.c act.item.c act.movement.c \
 	act.offensive.c act.other.c act.social.c act.wizard.c aedit.c \
@@ -47,7 +47,7 @@ CXREF_FILES = act.comm.c act.informative
 	mobact.c modify.c oasis.c oasis_copy.c oasis_delete.c oasis_list.c \
 	objsave.c oedit.c players.c random.c redit.c sedit.c shop.c \
 	spec_assign.c spec_procs.c spell_parser.c spells.c tedit.c utils.c \
-	weather.c zedit.c zmalloc.c
+	weather.c zedit.c zmalloc.c quest.c genqst.c qedit.c
 
 default: all
 
diff -BbuprN tbamud-3.55/src/Makefile.lcc tbamud-3.55+quests/src/Makefile.lcc
--- tbamud-3.55/src/Makefile.lcc	2008-01-16 23:21:14.000000000 +0000
+++ tbamud-3.55+quests/src/Makefile.lcc	2008-01-31 10:06:53.975672000 +0000
@@ -16,6 +16,9 @@ DISTDIR=c:\circle
 CFLAGS=-c -I$(LCCDIR)\include -DLCC_WIN32
 CC=lcc
 OBJS=\
+	genqst.obj \
+	qedit.obj \
+	quest.obj \
 	weather.obj \
 	utils.obj \
 	spells.obj \
@@ -58,6 +61,52 @@ LIBS=$(LCCDIR)\lib\wsock32.lib
 circle.exe:	$(OBJS)
         lcclnk  -subsystem console -o $(DISTDIR)\bin\circle.exe $(OBJS) $(LIBS)
 
+# Build GENQST.C
+GENQST_C=\
+    $(DISTDIR)\src\sysdep.h\
+    $(DISTDIR)\src\structs.h\
+    $(DISTDIR)\src\utils.h\
+    $(DISTDIR)\src\genolc.h\
+    $(DISTDIR)\src\genzon.h\
+    $(DISTDIR)\src\quest.h\
+    $(DISTDIR)\src\db.h\
+
+genqst.obj: $(GENQST_C) $(DISTDIR)\src\genqst.c
+    $(CC)  $(CFLAGS) $(DISTDIR)\src\genqst.c
+
+# Build QEDIT.C
+QEDIT_C=\
+    $(DISTDIR)\src\sysdep.h\
+    $(DISTDIR)\src\structs.h\
+    $(DISTDIR)\src\utils.h\
+    $(DISTDIR)\src\comm.h\
+    $(DISTDIR)\src\db.h\
+    $(DISTDIR)\src\oasis.h\
+    $(DISTDIR)\src\improved-edit.h\
+    $(DISTDIR)\src\screen.h\
+    $(DISTDIR)\src\genolc.h\
+    $(DISTDIR)\src\genzon.h\
+    $(DISTDIR)\src\interpreter.h\
+    $(DISTDIR)\src\quest.h\
+
+qedit.obj: $(QEDIT_C) $(DISTDIR)\src\qedit.c
+    $(CC)  $(CFLAGS) $(DISTDIR)\src\qedit.c
+
+# Build QUEST.C
+QUEST_C=\
+    $(DISTDIR)\src\sysdep.h\
+    $(DISTDIR)\src\structs.h\
+    $(DISTDIR)\src\utils.h\
+    $(DISTDIR)\src\comm.h\
+    $(DISTDIR)\src\handler.h\
+    $(DISTDIR)\src\interpreter.h\
+    $(DISTDIR)\src\db.h\
+    $(DISTDIR)\src\screen.h\
+    $(DISTDIR)\src\quest.h\
+
+quest.obj: $(QUEST_C) $(DISTDIR)\src\quest.c
+    $(CC)  $(CFLAGS) $(DISTDIR)\src\quest.c
+
 # Build WEATHER.C
 WEATHER_C=\
     $(DISTDIR)\src\sysdep.h\
diff -BbuprN tbamud-3.55/src/Makefile.msvc tbamud-3.55+quests/src/Makefile.msvc
--- tbamud-3.55/src/Makefile.msvc	2008-01-16 23:21:14.000000000 +0000
+++ tbamud-3.55+quests/src/Makefile.msvc	2008-01-31 10:08:32.631922000 +0000
@@ -40,7 +40,7 @@ OBJFILES = comm.obj act.comm.obj act.inf
         castle.obj class.obj config.obj constants.obj db.obj fight.obj graph.obj handler.obj \
         house.obj interpreter.obj limits.obj magic.obj mail.obj mobact.obj modify.obj \
         objsave.obj shop.obj spec_assign.obj spec_procs.obj spell_parser.obj \
-        spells.obj utils.obj weather.obj random.obj players.obj
+        spells.obj utils.obj weather.obj random.obj players.obj quest.obj qedit.obj genqst.obj
 
 default: circle.exe
         $(MAKE) circle.exe
@@ -153,3 +153,12 @@ utils.obj: utils.c conf.h sysdep.h struc
 weather.obj: weather.c conf.h sysdep.h structs.h utils.h comm.h handler.h \
   interpreter.h db.h
 	$(CC) -c $(CFLAGS) weather.c
+quest.obj: quest.c conf.h sysdep.h structs.h utils.h interpreter.h handler.h \
+  comm.h db.h screen.h quest.h
+	$(CC) -c $(CFLAGS) quest.c
+qedit.obj: qedit.c conf.h sysdep.h structs.h utils.h comm.h db.h oasis.h \
+  improved-edit.h screen.h genolc.h genzon.h interpreter.h quest.h
+	$(CC) -c $(CFLAGS) qedit.c
+genqst.obj: genqst.c conf.h sysdep.h structs.h utils.h db.h quest.h \
+  genolc.h genzon.h 
+	$(CC) -c $(CFLAGS) genqst.c
\ No newline at end of file
diff -BbuprN tbamud-3.55/src/Makefile.os2 tbamud-3.55+quests/src/Makefile.os2
--- tbamud-3.55/src/Makefile.os2	2008-01-16 23:21:16.000000000 +0000
+++ tbamud-3.55+quests/src/Makefile.os2	2008-01-31 10:09:20.850672000 +0000
@@ -26,7 +26,7 @@ OBJFILES = comm.o act.comm.o act.informa
         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 shop.o spec_assign.o spec_procs.o spell_parser.o \
-        spells.o utils.o weather.o random.o players.o
+        spells.o utils.o weather.o random.o players.o quest.o qedit.o genqst.o
 
 default: .accepted
         $(MAKE) ../bin/circle
@@ -194,3 +194,12 @@ utils.o: utils.c conf.h sysdep.h structs
 weather.o: weather.c conf.h sysdep.h structs.h utils.h comm.h handler.h \
   interpreter.h db.h
         $(CC) -c $(CFLAGS) weather.c
+quest.obj: quest.c conf.h sysdep.h structs.h utils.h interpreter.h handler.h \
+  comm.h db.h screen.h quest.h
+	$(CC) -c $(CFLAGS) quest.c
+qedit.obj: qedit.c conf.h sysdep.h structs.h utils.h comm.h db.h oasis.h \
+  improved-edit.h screen.h genolc.h genzon.h interpreter.h quest.h
+	$(CC) -c $(CFLAGS) qedit.c
+genqst.obj: genqst.c conf.h sysdep.h structs.h utils.h db.h quest.h \
+  genolc.h genzon.h 
+	$(CC) -c $(CFLAGS) genqst.c
\ No newline at end of file
diff -BbuprN tbamud-3.55/src/act.informative.c tbamud-3.55+quests/src/act.informative.c
--- tbamud-3.55/src/act.informative.c	2008-01-16 23:28:12.000000000 +0000
+++ tbamud-3.55+quests/src/act.informative.c	2008-01-31 08:42:49.006922000 +0000
@@ -827,6 +827,16 @@ ACMD(do_score)
     send_to_char(ch, "You need %d exp to reach your next level.\r\n",
 	level_exp(GET_CLASS(ch), GET_LEVEL(ch) + 1) - GET_EXP(ch));
 
+  send_to_char(ch, "You have earned %d quest points.\r\n", GET_QUESTPOINTS(ch));
+  send_to_char(ch, "You have completed %d quest%s, ",
+		    GET_NUM_QUESTS(ch),
+		    GET_NUM_QUESTS(ch) == 1 ? "" : "s");
+  if (GET_QUEST(ch) == NOTHING)
+    send_to_char(ch, "and you are not on a quest at the moment.\r\n");
+  else
+    send_to_char(ch, "and your current quest is %d.\r\n",
+                     GET_QUEST(ch) == NOTHING ? -1 : GET_QUEST(ch));
+
   playing_time = *real_time_passed((time(0) - ch->player.time.logon) +
 				  ch->player.time.played, 0);
   send_to_char(ch, "You have been playing for %d day%s and %d hour%s.\r\n",
diff -BbuprN tbamud-3.55/src/act.item.c tbamud-3.55+quests/src/act.item.c
--- tbamud-3.55/src/act.item.c	2008-01-16 23:21:16.000000000 +0000
+++ tbamud-3.55+quests/src/act.item.c	2008-01-31 08:45:40.663172000 +0000
@@ -20,6 +20,7 @@
 #include "constants.h"
 #include "dg_scripts.h"
 #include "oasis.h"
+#include "quest.h"
 
 /* local functions */
 int can_take_obj(struct char_data *ch, struct obj_data *obj);
@@ -619,6 +620,8 @@ void perform_give(struct char_data *ch, 
   act("You give $p to $N.", FALSE, ch, obj, vict, TO_CHAR);
   act("$n gives you $p.", FALSE, ch, obj, vict, TO_VICT);
   act("$n gives $p to $N.", TRUE, ch, obj, vict, TO_NOTVICT);
+
+  autoquest_trigger_check( ch, vict, obj, AQ_OBJ_RETURN);
 }
 
 /* utility function for give */
diff -BbuprN tbamud-3.55/src/act.other.c tbamud-3.55+quests/src/act.other.c
--- tbamud-3.55/src/act.other.c	2008-01-16 23:21:16.000000000 +0000
+++ tbamud-3.55+quests/src/act.other.c	2008-01-31 08:46:54.663172000 +0000
@@ -23,6 +23,7 @@
 #include "house.h"
 #include "constants.h"
 #include "dg_scripts.h"
+#include "quest.h"
 
 /* extern variables */
 extern struct spell_info_type spell_info[];
@@ -74,6 +75,8 @@ ACMD(do_quit)
   } else {
     act("$n has left the game.", TRUE, ch, 0, 0, TO_ROOM);
     mudlog(NRM, MAX(LVL_IMMORT, GET_INVIS_LEV(ch)), TRUE, "%s has quit the game.", GET_NAME(ch));
+    if (GET_QUEST_TIME(ch) != -1)
+      quest_timeout(ch);
     send_to_char(ch, "Goodbye, friend.. Come back soon!\r\n");
 
     /* We used to check here for duping attempts, but we may as well do it right
diff -BbuprN tbamud-3.55/src/act.wizard.c tbamud-3.55+quests/src/act.wizard.c
--- tbamud-3.55/src/act.wizard.c	2008-01-16 23:28:42.000000000 +0000
+++ tbamud-3.55+quests/src/act.wizard.c	2008-01-31 12:14:04.850672000 +0000
@@ -23,6 +23,7 @@
 #include "oasis.h"
 #include "dg_scripts.h"
 #include "shop.h"
+#include "quest.h"
 
 /* external vars */
 extern FILE *player_fl;
@@ -893,6 +894,12 @@ void do_stat_character(struct char_data 
 
     sprintbitarray(PRF_FLAGS(k), preference_bits, PR_ARRAY_MAX, buf);
     send_to_char(ch, "PRF: %s%s%s\r\n", CCGRN(ch, C_NRM), buf, CCNRM(ch, C_NRM));
+
+    send_to_char(ch, "Quest Points: [%9d] Quests Completed: [%5d]\r\n",
+		    GET_QUESTPOINTS(ch), GET_NUM_QUESTS(ch));
+    if (GET_QUEST(ch) != NOTHING)
+      send_to_char(ch, "Current Quest: [%5d] Time Left: [%5d]\r\n",
+		   GET_QUEST(ch), GET_QUEST_TIME(ch));
   }
 
   if (IS_MOB(k))
@@ -2581,7 +2588,7 @@ ACMD(do_show)
 	"  %5d objects          %5d prototypes\r\n"
 	"  %5d rooms            %5d zones\r\n"
         "  %5d triggers         %5d shops\r\n"
-      	"  %5d large bufs\r\n"
+      	"  %5d large bufs       %5d autoquests\r\n"
 	"  %5d buf switches     %5d overflows\r\n",
 	i, con,
 	top_of_p_table + 1,
@@ -2589,7 +2596,7 @@ ACMD(do_show)
 	k, top_of_objt + 1,
 	top_of_world + 1, top_of_zone_table + 1,
 	top_of_trigt + 1, top_shop + 1,
-	buf_largecount,
+	buf_largecount, total_quests,
 	buf_switches, buf_overflows
 	);
     break;
@@ -2756,12 +2763,13 @@ ACMD(do_show)
    { "weight",		LVL_BUILDER,	BOTH,	NUMBER },
    { "wis", 		LVL_BUILDER, 	BOTH, 	NUMBER },
    { "questpoints",     LVL_GOD,        PC,     NUMBER },
+   { "questhistory",    LVL_GOD,        PC,   NUMBER },
    { "\n", 0, BOTH, MISC }
   };
 
 int perform_set(struct char_data *ch, struct char_data *vict, int mode, char *val_arg)
 {
-  int i, on = 0, off = 0, value = 0;
+  int i, on = 0, off = 0, value = 0, qvnum;
   room_rnum rnum;
   room_vnum rvnum;
 
@@ -3141,6 +3149,23 @@ int perform_set(struct char_data *ch, st
     case 54: /* questpoints */
       GET_QUESTPOINTS(vict) = RANGE(0, 100000000);
       break;
+    case 55: /* questhistory */
+      qvnum = atoi(val_arg);
+      if (real_quest(qvnum) == NOTHING) {
+        send_to_char(ch, "That quest doesn't exist.\r\n");
+        return FALSE;
+      } else {
+        if (is_complete(vict, qvnum)) {
+          remove_completed_quest(vict, qvnum);
+          send_to_char(ch, "Quest %d removed from history for player %s.\r\n",
+			qvnum, GET_NAME(vict));
+        } else {
+          add_completed_quest(vict, qvnum);
+          send_to_char(ch, "Quest %d added to history for player %s.\r\n",
+			qvnum, GET_NAME(vict));
+        }
+        break;
+      }
     default:
       send_to_char(ch, "Can't set that!\r\n");
       return (0);
diff -BbuprN tbamud-3.55/src/comm.c tbamud-3.55+quests/src/comm.c
--- tbamud-3.55/src/comm.c	2008-01-16 23:21:16.000000000 +0000
+++ tbamud-3.55+quests/src/comm.c	2008-01-31 08:59:29.756922000 +0000
@@ -61,6 +61,7 @@
 #include "genolc.h"
 #include "dg_scripts.h"
 #include "dg_event.h"
+#include "quest.h"
 
 #ifdef HAVE_ARPA_TELNET_H
 #include <arpa/telnet.h>
@@ -969,11 +970,12 @@ void heartbeat(int heart_pulse)
   if (!(heart_pulse % PULSE_VIOLENCE))
     perform_violence();
 
-  if (!(heart_pulse % (SECS_PER_MUD_HOUR * PASSES_PER_SEC))) {
+  if (!(heart_pulse % (SECS_PER_MUD_HOUR * PASSES_PER_SEC))) {  /* Tick ! */
     weather_and_time(1);
     check_time_triggers();
     affect_update();
     point_update();
+    check_timed_quests();
   }
 
   if (CONFIG_AUTO_SAVE && !(heart_pulse % PULSE_AUTOSAVE)) {	/* 1 minute */
diff -BbuprN tbamud-3.55/src/constants.c tbamud-3.55+quests/src/constants.c
--- tbamud-3.55/src/constants.c	2008-01-16 23:21:16.000000000 +0000
+++ tbamud-3.55+quests/src/constants.c	2008-01-31 09:00:51.975672000 +0000
@@ -362,6 +362,7 @@ const char *extra_bits[] = {
   "ANTI_THIEF",
   "ANTI_WARRIOR",
   "NO_SELL",
+  "QUEST_ITEM",
   "\n"
 };
 
diff -BbuprN tbamud-3.55/src/db.c tbamud-3.55+quests/src/db.c
--- tbamud-3.55/src/db.c	2008-01-16 23:21:14.000000000 +0000
+++ tbamud-3.55+quests/src/db.c	2008-01-31 12:16:56.694422000 +0000
@@ -25,6 +25,7 @@
 #include "oasis.h"
 #include "dg_scripts.h"
 #include "dg_event.h"
+#include "quest.h"
 
 /*  declarations of most of the 'global' variables */
 struct config_data config_info; /* Game configuration list.	 */
@@ -56,6 +57,9 @@ int dg_owner_purged;            /* For c
 struct shop_data *shop_index;   /* index table for shops         */
 int top_shop = -1;              /* top of shop table             */
 
+struct aq_data *aquest_table;   /* Autoquests table              */
+qst_rnum total_quests = 0;      /* top of autoquest table        */
+
 int no_mail = 0;		/* mail disabled?		 */
 int mini_mud = 0;		/* mini-mud mode?		 */
 int no_rent_check = 0;		/* skip rent check on boot?	 */
@@ -472,6 +476,9 @@ void boot_world(void)
   if (!no_specials) {
     log("Loading shops.");
     index_boot(DB_BOOT_SHP);
+
+    log("Loading quests.");
+    index_boot(DB_BOOT_QST);
   }
 }
 
@@ -582,6 +589,9 @@ void destroy_db(void)
   /* Shops */
   destroy_shops();
 
+  /* Quests */
+  destroy_quests();
+
   /* Zones */
 #define THIS_CMD zone_table[cnt].cmd[itr]
 
@@ -706,6 +716,8 @@ void boot_db(void)
     assign_objects();
     log("   Rooms.");
     assign_rooms();
+    log("   Questmasters.");
+    assign_the_quests();
   }
 
   log("Assigning spell and skill levels.");
@@ -914,6 +926,9 @@ void index_boot(int mode)
   case DB_BOOT_TRG:
     prefix = TRG_PREFIX;
     break;
+  case DB_BOOT_QST:
+    prefix = QST_PREFIX;
+    break;
   default:
     log("SYSERR: Unknown subcommand %d to index_boot!", mode);
     exit(1);
@@ -954,7 +969,7 @@ void index_boot(int mode)
 
   /* Exit if 0 records, unless this is shops */
   if (!rec_count) {
-    if (mode == DB_BOOT_SHP)
+    if (mode == DB_BOOT_SHP || mode == DB_BOOT_QST)
       return;
     log("SYSERR: boot error - 0 records counted in %s/%s.", prefix,
 	index_filename);
@@ -995,6 +1010,11 @@ void index_boot(int mode)
     size[0] = sizeof(struct help_index_element) * rec_count;
     log("   %d entries, %d bytes.", rec_count, size[0]);
     break;
+  case DB_BOOT_QST:
+    CREATE(aquest_table, struct aq_data, rec_count);
+    size[0] = sizeof(struct aq_data) * rec_count;
+    log("   %d entries, %d bytes.", rec_count, size[0]);
+    break;
   }
 
   rewind(db_index);
@@ -1010,6 +1030,7 @@ void index_boot(int mode)
     case DB_BOOT_OBJ:
     case DB_BOOT_MOB:
     case DB_BOOT_TRG:
+    case DB_BOOT_QST:
       discrete_load(db_file, mode, buf2);
       break;
     case DB_BOOT_ZON:
@@ -1040,7 +1061,7 @@ void discrete_load(FILE *fl, int mode, c
   int nr = -1, last;
   char line[READ_SIZE];
 
-  const char *modes[] = {"world", "mob", "obj", "ZON", "SHP", "HLP", "trg"};
+  const char *modes[] = {"world", "mob", "obj", "ZON", "SHP", "HLP", "trg", "qst"};
   /* modes positions correspond to DB_BOOT_xxx in db.h */
 
   for (;;) {
@@ -1083,6 +1104,9 @@ void discrete_load(FILE *fl, int mode, c
 	case DB_BOOT_OBJ:
 	  strlcpy(line, parse_object(fl, nr), sizeof(line));
 	  break;
+	case DB_BOOT_QST:
+	  parse_quest(fl, nr);
+	  break;
 	}
     } else {
       log("SYSERR: Format error in %s file %s near %s #%d", modes[mode],
@@ -2747,6 +2771,8 @@ void free_char(struct char_data *ch)
       free(ch->player_specials->poofin);
     if (ch->player_specials->poofout)
       free(ch->player_specials->poofout);
+    if (ch->player_specials->saved.completed_quests)
+      free(ch->player_specials->saved.completed_quests);
     if (GET_HOST(ch))
       free(GET_HOST(ch));
     if (IS_NPC(ch))
@@ -2996,6 +3022,10 @@ void init_char(struct char_data *ch)
   ch->player.long_descr = NULL;
   ch->player.description = NULL;
 
+  GET_NUM_QUESTS(ch) = 0;
+  ch->player_specials->saved.completed_quests = NULL;
+  GET_QUEST(ch) = -1;
+
   ch->player.time.birth = time(0);
   ch->player.time.logon = time(0);
   ch->player.time.played = 0;
diff -BbuprN tbamud-3.55/src/db.h tbamud-3.55+quests/src/db.h
--- tbamud-3.55/src/db.h	2008-01-16 23:21:14.000000000 +0000
+++ tbamud-3.55+quests/src/db.h	2008-01-31 09:10:29.241297000 +0000
@@ -16,6 +16,7 @@
 #define DB_BOOT_SHP	4
 #define DB_BOOT_HLP	5
 #define DB_BOOT_TRG	6
+#define DB_BOOT_QST 7
 
 #if defined(CIRCLE_MACINTOSH)
 #define LIB_WORLD	":world:"
@@ -76,6 +77,7 @@
 #define SHP_PREFIX	LIB_WORLD"shp"SLASH	/* shop definitions	*/
 #define TRG_PREFIX	LIB_WORLD"trg"SLASH	/* trigger files	*/
 #define HLP_PREFIX      LIB_TEXT"help"SLASH     /* Help files           */
+#define QST_PREFIX      LIB_WORLD"qst"SLASH     /* quest files          */
 
 #define CREDITS_FILE	LIB_TEXT"credits" /* for the 'credits' command	*/
 #define NEWS_FILE	LIB_TEXT"news"	/* for the 'news' command	*/
diff -BbuprN tbamud-3.55/src/dg_variables.c tbamud-3.55+quests/src/dg_variables.c
--- tbamud-3.55/src/dg_variables.c	2008-01-16 23:21:16.000000000 +0000
+++ tbamud-3.55+quests/src/dg_variables.c	2008-01-31 09:14:08.460047000 +0000
@@ -853,7 +853,7 @@ void find_replacement(void *go, struct s
           }
           break;
         case 'q':
-          if (!str_cmp(field, "questpoints")) {
+          if (!str_cmp(field, "questpoints") || !str_cmp(field, "qp") || !str_cmp(field, "qpnts")) {
             if (subfield && *subfield) {
               int addition = atoi(subfield);
               GET_QUESTPOINTS(c) += addition;
diff -BbuprN tbamud-3.55/src/fight.c tbamud-3.55+quests/src/fight.c
--- tbamud-3.55/src/fight.c	2008-01-16 23:21:14.000000000 +0000
+++ tbamud-3.55+quests/src/fight.c	2008-01-31 09:15:53.710047000 +0000
@@ -20,6 +20,7 @@
 #include "screen.h"
 #include "constants.h"
 #include "dg_scripts.h"
+#include "quest.h"
 
 /* Structures */
 struct char_data *combat_list = NULL;	/* head of l-list of fighting chars */
@@ -363,10 +364,18 @@ void raw_kill(struct char_data * ch, str
   } else
     death_cry(ch);
 
+  if (killer)
+    autoquest_trigger_check(killer, ch, NULL, AQ_MOB_KILL);
+
   update_pos(ch);
 
   make_corpse(ch);
   extract_char(ch);
+
+  if (killer) {
+    autoquest_trigger_check(killer, NULL, NULL, AQ_MOB_SAVE);
+    autoquest_trigger_check(killer, NULL, NULL, AQ_ROOM_CLEAR);
+  }
 }
 
 void die(struct char_data * ch, struct char_data * killer)
diff -BbuprN tbamud-3.55/src/genolc.c tbamud-3.55+quests/src/genolc.c
--- tbamud-3.55/src/genolc.c	2008-01-16 23:21:14.000000000 +0000
+++ tbamud-3.55+quests/src/genolc.c	2008-01-31 09:17:34.069422000 +0000
@@ -25,6 +25,7 @@
 #include "dg_olc.h"
 #include "constants.h"
 #include "interpreter.h"
+#include "quest.h"
 
 int save_config( IDXTYPE nowhere );        /* Exported from cedit.c */
 
@@ -43,6 +44,7 @@ struct {
   { SL_WLD, save_rooms, "room" },
   { SL_ZON, save_zone, "zone" },
   { SL_CFG, save_config, "config" },
+  { SL_QST, save_quests, "quest" },
   { SL_ACT, NULL, "social" },
   { SL_HLP, NULL, "help" },
   { -1, NULL, NULL },
diff -BbuprN tbamud-3.55/src/genolc.h tbamud-3.55+quests/src/genolc.h
--- tbamud-3.55/src/genolc.h	2008-01-16 23:21:14.000000000 +0000
+++ tbamud-3.55+quests/src/genolc.h	2008-01-31 09:17:49.678797000 +0000
@@ -36,7 +36,8 @@ extern struct save_list_data *save_list;
 #define SL_WLD	3
 #define SL_ZON	4
 #define SL_CFG	5
-#define SL_MAX  5	
+#define SL_QST  6
+#define SL_MAX  6
 #define SL_ACT SL_MAX + 1 /* must be above MAX */ 
 #define SL_HLP SL_MAX + 2
 
diff -BbuprN tbamud-3.55/src/genqst.c tbamud-3.55+quests/src/genqst.c
--- tbamud-3.55/src/genqst.c	1970-01-01 00:00:00.000000000 +0000
+++ tbamud-3.55+quests/src/genqst.c	2008-01-31 12:32:14.210047000 +0000
@@ -0,0 +1,267 @@
+/* ***********************************************************************
+*    File:   genqst.c                                 Part of CircleMUD  *
+* Version:   2.0 (November 2005) Written for CircleMud CWG / Suntzu      *
+* Purpose:   To provide special quest-related code.                      *
+* Copyright: Kenneth Ray                                                 *
+* Original Version Details:                                              *
+* Copyright 1996 by Harvey Gilpin					 *
+* Copyright 1997-2001 by George Greer (greerga@circlemud.org)		 *
+************************************************************************ */
+
+#include "conf.h"
+#include "sysdep.h"
+#include "structs.h"
+#include "utils.h"
+#include "db.h"
+#include "quest.h"
+#include "genolc.h"
+#include "genzon.h"
+
+void create_world_index(int znum, const char *type);
+
+extern zone_rnum top_of_zone_table;
+
+/*-------------------------------------------------------------------*/
+
+int copy_quest(struct aq_data *to, struct aq_data *from, int free_old_strings)
+{
+  int i;
+  if (free_old_strings)
+    free_quest_strings(to);
+  to->vnum       = from->vnum;
+  to->flags      = from->flags;
+  to->type       = from->type;
+  to->qm         = from->qm;
+  to->target     = from->target;
+  to->prereq     = from->prereq;
+  to->prev_quest = from->prev_quest;
+  to->next_quest = from->next_quest;
+  for (i = 0; i < 7; i++){
+    to->value[i] = from->value[i];
+  }
+  to->gold_reward = from->gold_reward;
+  to->exp_reward  = from->exp_reward;
+  to->obj_reward  = from->obj_reward;
+  to->func        = from->func;
+  return copy_quest_strings(to, from);
+}
+
+int copy_quest_strings(struct aq_data *to, struct aq_data *from)
+{
+  if (from == NULL || to == NULL) {
+    log("SYSERR: GenQST: copy_quest_strings: Null values passed.");
+    return FALSE;
+  }
+  to->name = str_udup(from->name);
+  to->desc = str_udup(from->desc);
+  to->info = str_udup(from->info);
+  to->done = str_udup(from->done);
+  to->quit = str_udup(from->quit);
+  return TRUE;
+}
+
+void free_quest_strings(struct aq_data *quest)
+{
+  if (quest->name)
+    free(quest->name);
+  if (quest->desc)
+    free(quest->desc);
+  if (quest->info)
+    free(quest->info);
+  if (quest->done)
+    free(quest->done);
+  if (quest->quit)
+    free(quest->quit);
+}
+
+void free_quest(struct aq_data *quest)
+{
+  free_quest_strings(quest);
+  free(quest);
+}
+
+/*-------------------------------------------------------------------*/
+
+int add_quest(struct aq_data *nqst)
+{
+  qst_rnum rnum;
+  zone_rnum rznum = real_zone_by_thing(nqst->vnum);
+
+  /* The quest already exists, just update it.  */
+  if ((rnum = real_quest(nqst->vnum)) != NOWHERE) {
+    copy_quest(&aquest_table[rnum], nqst, TRUE);
+  } else {
+    /* increase the number of quest table entries */
+    total_quests++;
+    RECREATE(aquest_table, struct aq_data, total_quests );
+    /* Initialise top quest strings to null */
+    QST_NAME(total_quests - 1) = NULL;
+    QST_DESC(total_quests - 1) = NULL;
+    QST_INFO(total_quests - 1) = NULL;
+    QST_DONE(total_quests - 1) = NULL;
+    QST_QUIT(total_quests - 1) = NULL;
+    /* Now process enties from the top down to see where the new one goes */
+    for (rnum = total_quests - 1; rnum > 0; rnum--) {
+      if (nqst->vnum > QST_NUM(rnum - 1))
+        break; //found the place
+      aquest_table[rnum] = aquest_table[rnum - 1]; //shift quest up one
+    }
+    copy_quest(&aquest_table[rnum], nqst, FALSE);
+  }
+  /* Make sure we assign spec procs to the questmaster */
+  if (mob_index[QST_MASTER(rnum)].func &&
+      mob_index[QST_MASTER(rnum)].func != questmaster)
+    QST_FUNC(rnum) = mob_index[QST_MASTER(rnum)].func;
+  mob_index[QST_MASTER(rnum)].func = questmaster;
+
+  /* And make sure we save the updated quest information to disk */
+  if (rznum != NOWHERE)
+    add_to_save_list(zone_table[rznum].number, SL_QST);
+  else
+    mudlog(BRF, LVL_BUILDER, TRUE,
+           "SYSERR: GenOLC: Cannot determine quest zone.");
+
+  return rnum;
+}
+
+/*-------------------------------------------------------------------*/
+
+int delete_quest(qst_rnum rnum)
+{
+  qst_rnum i;
+  zone_rnum rznum = real_zone_by_thing(QST_NUM(rnum));
+  mob_rnum qm = QST_MASTER(rnum);
+  SPECIAL (*tempfunc);
+  int  quests_remaining = 0;
+
+  if (rnum >= total_quests)
+    return FALSE;
+  log("GenOLC: delete_quest: Deleting quest #%d (%s).",
+       QST_NUM(rnum), QST_NAME(rnum));
+  /* make a note of the quest master's secondary spec proc */
+  tempfunc = QST_FUNC(rnum);
+
+
+  free_quest_strings(&aquest_table[rnum]);
+  for (i = rnum; i < total_quests - 1; i++) {
+    aquest_table[i] = aquest_table[i + 1];
+  }
+  total_quests--;
+  RECREATE(aquest_table, struct aq_data, total_quests);
+
+  if (rznum != NOWHERE)
+     add_to_save_list(zone_table[rznum].number, SL_QST);
+  else
+    mudlog(BRF, LVL_BUILDER, TRUE,
+           "SYSERR: GenOLC: Cannot determine quest zone.");
+  /* does the questmaster mob have any quests left? */
+  if (qm != NOBODY) {
+    for (i = 0; i < total_quests; i++) {
+      if (QST_MASTER(i) == qm)
+        quests_remaining++;
+    }
+    if (quests_remaining == 0)
+      mob_index[qm].func = tempfunc; // point back to original spec proc
+  }
+  return TRUE;
+}
+
+/*-------------------------------------------------------------------*/
+
+int save_quests(zone_rnum zone_num)
+{
+  FILE *sf;
+  char filename[128], oldname[128], quest_flags[MAX_STRING_LENGTH];
+  char quest_desc[MAX_STRING_LENGTH], quest_info[MAX_STRING_LENGTH];
+  char quest_done[MAX_STRING_LENGTH], quest_quit[MAX_STRING_LENGTH];
+  int i, num_quests = 0;
+
+#if CIRCLE_UNSIGNED_INDEX
+  if (zone_num == NOWHERE || zone_num > top_of_zone_table) {
+#else
+  if (zone_num < 0 || zone_num > top_of_zone_table) {
+#endif
+    log("SYSERR: GenOLC: save_quests: Invalid zone number %d passed! (0-%d)",
+         zone_num, top_of_zone_table);
+    return FALSE;
+  }
+
+  log("GenOLC: save_quests: Saving quests in zone #%d (%d-%d).",
+        zone_table[zone_num].number,
+	genolc_zone_bottom(zone_num), zone_table[zone_num].top);
+
+  snprintf(filename, sizeof(filename), "%s/%d.new",
+	QST_PREFIX, zone_table[zone_num].number);
+  if (!(sf = fopen(filename, "w"))) {
+    perror("SYSERR: save_quests");
+    return FALSE;
+  }
+  for (i = genolc_zone_bottom(zone_num); i <= zone_table[zone_num].top; i++) {
+    qst_rnum rnum;
+    if ((rnum = real_quest(i)) != NOTHING) {
+      /* Copy the text strings and strip off trailing newlines. */
+      strncpy(quest_desc, QST_DESC(rnum) ? QST_DESC(rnum) : "undefined",
+              sizeof(quest_desc)-1 );
+      strncpy(quest_info, QST_INFO(rnum) ? QST_INFO(rnum) : "undefined",
+              sizeof(quest_info)-1 );
+      strncpy(quest_done, QST_DONE(rnum) ? QST_DONE(rnum) : "undefined",
+              sizeof(quest_done)-1 );
+      strncpy(quest_quit, QST_QUIT(rnum) ? QST_QUIT(rnum) : "undefined",
+              sizeof(quest_quit)-1 );
+      strip_cr(quest_desc);
+      strip_cr(quest_info);
+      strip_cr(quest_done);
+      strip_cr(quest_quit);
+      /* Save the quest details to the file.  */
+      sprintascii(quest_flags, QST_FLAGS(rnum));
+      fprintf(sf,
+	"#%d\n"
+        "%s%c\n"
+        "%s%c\n"
+        "%s%c\n"
+        "%s%c\n"
+        "%s%c\n"
+        "%d %d %s %d %d %d %d\n"
+        "%d %d %d %d %d %d %d\n"
+        "%d %d %d\n"
+        "S\n",
+        QST_NUM(rnum),
+        QST_NAME(rnum) ? QST_NAME(rnum) : "Untitled", STRING_TERMINATOR,
+        quest_desc, STRING_TERMINATOR,
+	quest_info, STRING_TERMINATOR,
+	quest_done, STRING_TERMINATOR,
+	quest_quit, STRING_TERMINATOR,
+        QST_TYPE(rnum),
+	QST_MASTER(rnum) == NOBODY ? -1 : mob_index[QST_MASTER(rnum)].vnum,
+	quest_flags,
+	QST_TARGET(rnum) == NOTHING ? -1 : QST_TARGET(rnum),
+	QST_PREV(rnum)   == NOTHING ? -1 : QST_PREV(rnum),
+	QST_NEXT(rnum)   == NOTHING ? -1 : QST_NEXT(rnum),
+	QST_PREREQ(rnum) == NOTHING ? -1 : QST_PREREQ(rnum),
+        QST_POINTS(rnum), QST_PENALTY(rnum), QST_MINLEVEL(rnum),
+        QST_MAXLEVEL(rnum), QST_TIME(rnum),
+	QST_RETURNMOB(rnum) == NOBODY ? -1 : QST_RETURNMOB(rnum),
+	QST_QUANTITY(rnum), QST_GOLD(rnum), QST_EXP(rnum), QST_OBJ(rnum)
+      );
+      num_quests++;
+    }
+  }
+  /* Write the final line and close it.  */
+  fprintf(sf, "$~\n");
+  fclose(sf);
+
+  /* Old file we're replacing. */
+  snprintf(oldname, sizeof(oldname), "%s/%d.qst",
+           QST_PREFIX, zone_table[zone_num].number);
+  remove(oldname);
+  rename(filename, oldname);
+
+  /* Do we need to update the index file? */
+  if (num_quests > 0)
+    create_world_index(zone_table[zone_num].number, "qst");
+
+  if (in_save_list(zone_table[zone_num].number, SL_QST))
+    remove_from_save_list(zone_table[zone_num].number, SL_QST);
+  return TRUE;
+}
+
diff -BbuprN tbamud-3.55/src/genshp.c tbamud-3.55+quests/src/genshp.c
--- tbamud-3.55/src/genshp.c	2008-01-16 23:21:16.000000000 +0000
+++ tbamud-3.55+quests/src/genshp.c	2008-01-31 12:19:27.256922000 +0000
@@ -24,6 +24,9 @@ void copy_shop_type_list(struct shop_buy
 void free_shop_strings(struct shop_data *shop);
 void free_shop_type_list(struct shop_buy_data **list);
 
+/* External Functions */
+void create_world_index(int znum, const char *type);
+
 void copy_shop(struct shop_data *tshop, struct shop_data *fshop, int free_old_strings)
 {
   /* Copy basic information over. */
@@ -343,7 +346,7 @@ int add_shop(struct shop_data *nshp)
 
 int save_shops(zone_rnum zone_num)
 {
-  int i, j, rshop;
+  int i, j, rshop, num_shops = 0;
   FILE *shop_file;
   char fname[128], oldname[128];
   struct shop_data *shop;
@@ -424,6 +427,7 @@ int save_shops(zone_rnum zone_num)
       /* Save open/closing times. */
       fprintf(shop_file, "%d\n%d\n%d\n%d\n", S_OPEN1(shop), S_CLOSE1(shop),
 		S_OPEN2(shop), S_CLOSE2(shop));
+      num_shops++;
     }
   }
   fprintf(shop_file, "$~\n");
@@ -432,6 +436,9 @@ int save_shops(zone_rnum zone_num)
   remove(oldname);
   rename(fname, oldname);
 
+  if (num_shops > 0)
+    create_world_index(zone_table[zone_num].number, "shp");
+
   if (in_save_list(zone_table[zone_num].number, SL_SHP))
     remove_from_save_list(zone_table[zone_num].number, SL_SHP);
   return TRUE;
diff -BbuprN tbamud-3.55/src/genzon.c tbamud-3.55+quests/src/genzon.c
--- tbamud-3.55/src/genzon.c	2008-01-16 23:21:14.000000000 +0000
+++ tbamud-3.55+quests/src/genzon.c	2008-01-31 09:36:08.069422000 +0000
@@ -134,6 +134,16 @@ zone_rnum create_new_zone(zone_vnum vzon
   fprintf(fp, "$~\n");
   fclose(fp);
 
+   /* Create the quests file */
+  snprintf(buf, sizeof(buf), "%s/%d.qst", QST_PREFIX, vzone_num);
+  if (!(fp = fopen(buf, "w"))) {
+    mudlog(BRF, LVL_IMPL, TRUE, "SYSERR: OLC: Can't write new quest file");
+    *error = "Could not write quest file.\r\n";
+    return NOWHERE;
+  }
+  fprintf(fp, "$~\n");
+  fclose(fp);
+
   /* Update index files. */
   create_world_index(vzone_num, "zon");
   create_world_index(vzone_num, "wld");
@@ -141,6 +151,7 @@ zone_rnum create_new_zone(zone_vnum vzon
   create_world_index(vzone_num, "obj");
   create_world_index(vzone_num, "shp");
   create_world_index(vzone_num, "trg");
+  create_world_index(vzone_num, "qst");
 
   /* Make a new zone in memory. This was the source of all the zedit new 
    * crashes. It was happily overwriting the stack.  This new loop by Andrew 
@@ -212,6 +223,9 @@ void create_world_index(int znum, const 
   case 't':
     prefix = TRG_PREFIX;
     break;
+  case 'q':
+    prefix = QST_PREFIX;
+    break;
   default:
     /* Caller messed up. */
     return;
@@ -242,6 +256,12 @@ void create_world_index(int znum, const 
       if (num > znum) {
 	found = TRUE;
 	fprintf(newfile, "%s\n", buf1);
+      } else if (num == znum) {
+        /* index file already had an entry for this zone. */
+        fclose(oldfile);
+        fclose(newfile);
+        remove(new_name);
+        return;
       }
     }
     fprintf(newfile, "%s\n", buf);
diff -BbuprN tbamud-3.55/src/handler.c tbamud-3.55+quests/src/handler.c
--- tbamud-3.55/src/handler.c	2008-01-16 23:21:16.000000000 +0000
+++ tbamud-3.55+quests/src/handler.c	2008-01-31 09:38:02.944422000 +0000
@@ -18,6 +18,7 @@
 #include "interpreter.h"
 #include "spells.h"
 #include "dg_scripts.h"
+#include "quest.h"
 
 /* local vars */
 int extractions_pending = 0;
@@ -412,6 +413,9 @@ void char_to_room(struct char_data *ch, 
     world[room].people = ch;
     IN_ROOM(ch) = room;
 
+    autoquest_trigger_check(ch, 0, 0, AQ_ROOM_FIND);
+    autoquest_trigger_check(ch, 0, 0, AQ_MOB_FIND);
+
     if (GET_EQ(ch, WEAR_LIGHT))
       if (GET_OBJ_TYPE(GET_EQ(ch, WEAR_LIGHT)) == ITEM_LIGHT)
 	if (GET_OBJ_VAL(GET_EQ(ch, WEAR_LIGHT), 2))	/* Light ON */
@@ -436,6 +440,8 @@ void obj_to_char(struct obj_data *object
     IS_CARRYING_W(ch) += GET_OBJ_WEIGHT(object);
     IS_CARRYING_N(ch)++;
 
+    autoquest_trigger_check(ch, NULL, object, AQ_OBJ_FIND);
+
     /* set flag for crash-save system, but not on mobs! */
     if (!IS_NPC(ch))
       SET_BIT_AR(PLR_FLAGS(ch), PLR_CRASH);
diff -BbuprN tbamud-3.55/src/interpreter.c tbamud-3.55+quests/src/interpreter.c
--- tbamud-3.55/src/interpreter.c	2008-01-16 23:27:40.000000000 +0000
+++ tbamud-3.55+quests/src/interpreter.c	2008-01-31 09:45:06.788172000 +0000
@@ -26,6 +26,7 @@
 #include "improved-edit.h"
 #include "dg_scripts.h"
 #include "constants.h"
+#include "quest.h"
 
 /* external variables */
 extern room_rnum r_mortal_start_room;
@@ -164,6 +165,7 @@ ACMD(do_practice);
 ACMD(do_purge);
 ACMD(do_put);
 ACMD(do_qcomm);
+ACMD(do_quest);
 ACMD(do_quit);
 ACMD(do_reboot);
 ACMD(do_remove);
@@ -397,9 +399,11 @@ cpp_extern const struct command_info cmd
   { "prompt"   , "pro"     , POS_DEAD    , do_display  , 0, 0 },
   { "purge"    , "purge"   , POS_DEAD    , do_purge    , LVL_BUILDER, 0 },
 
+  { "qedit"    , "qedit"   , POS_DEAD    , do_oasis_qedit, LVL_BUILDER, 0 },
+  { "qlist"    , "qlist"   , POS_DEAD    , do_oasis_list, LVL_BUILDER, SCMD_OASIS_QLIST },
   { "quaff"    , "qua"     , POS_RESTING , do_use      , 0, SCMD_QUAFF },
   { "qecho"    , "qec"     , POS_DEAD    , do_qcomm    , LVL_GOD, SCMD_QECHO },
-  { "quest"    , "que"     , POS_DEAD    , do_gen_tog  , 0, SCMD_QUEST },
+  { "quest"    , "que"	   , POS_DEAD    , do_quest    , 0, 0 },
   { "qui"      , "qui"     , POS_DEAD    , do_quit     , 0, 0 },
   { "quit"     , "quit"    , POS_DEAD    , do_quit     , 0, SCMD_QUIT },
   { "qsay"     , "qsay"    , POS_RESTING , do_qcomm    , 0, SCMD_QSAY },
@@ -1309,6 +1313,7 @@ void nanny(struct descriptor_data *d, ch
     { CON_TRIGEDIT, trigedit_parse },
     { CON_AEDIT, aedit_parse },
     { CON_HEDIT,    hedit_parse },
+    { CON_QEDIT, qedit_parse },
     { -1, NULL }
   };
 
diff -BbuprN tbamud-3.55/src/interpreter.h tbamud-3.55+quests/src/interpreter.h
--- tbamud-3.55/src/interpreter.h	2008-01-16 23:21:16.000000000 +0000
+++ tbamud-3.55+quests/src/interpreter.h	2008-01-31 09:45:31.600672000 +0000
@@ -219,6 +219,7 @@ struct alias_data {
 #define SCMD_OASIS_SLIST       3
 #define SCMD_OASIS_ZLIST       4
 #define SCMD_OASIS_TLIST       5
+#define SCMD_OASIS_QLIST       6
 
 /* do_last */
 #define SCMD_LIST_ALL 1
diff -BbuprN tbamud-3.55/src/modify.c tbamud-3.55+quests/src/modify.c
--- tbamud-3.55/src/modify.c	2008-01-16 23:21:16.000000000 +0000
+++ tbamud-3.55+quests/src/modify.c	2008-01-31 10:12:06.147547000 +0000
@@ -21,6 +21,7 @@
 #include "boards.h"
 #include "improved-edit.h"
 #include "oasis.h"
+#include "quest.h"
 
 void show_string(struct descriptor_data *d, char *input);
 
@@ -151,6 +152,7 @@ void string_add(struct descriptor_data *
         case CON_PLR_DESC:
         case CON_TRIGEDIT:
         case CON_HEDIT:
+        case CON_QEDIT:
 	  free(*d->str);
           *d->str = d->backstr;
           d->backstr = NULL;
@@ -190,6 +192,7 @@ void string_add(struct descriptor_data *
       { CON_PLR_DESC , exdesc_string_cleanup },
       { CON_PLAYING, playing_string_cleanup },
       { CON_HEDIT, hedit_string_cleanup },
+      { CON_QEDIT  , qedit_string_cleanup },
       { -1, NULL }
     };
 
diff -BbuprN tbamud-3.55/src/oasis.c tbamud-3.55+quests/src/oasis.c
--- tbamud-3.55/src/oasis.c	2008-01-16 23:21:16.000000000 +0000
+++ tbamud-3.55+quests/src/oasis.c	2008-01-31 10:14:25.725672000 +0000
@@ -22,6 +22,7 @@
 #include "oasis.h"
 #include "screen.h"
 #include "dg_olc.h"
+#include "quest.h"
 
 /* External Functions */
 int is_name(const char *str, const char *namelist);
@@ -40,6 +41,7 @@ struct olc_scmd_info_t {
   { "trigger",  CON_TRIGEDIT },
   { "action",   CON_AEDIT },
   { "help",     CON_HEDIT },
+  { "quest",     CON_QEDIT },
   { "\n",	-1	  }
 };
 
@@ -125,6 +127,20 @@ void cleanup_olc(struct descriptor_data 
   if (OLC_SHOP(d))
       free_shop(OLC_SHOP(d));
 
+  /* Check for a quest. */
+  if (OLC_QUEST(d)) {
+    switch (cleanup_type) {
+      case CLEANUP_ALL:
+        free_quest(OLC_QUEST(d));
+        break;
+      case CLEANUP_STRUCTS:
+        free(OLC_QUEST(d));
+        break;
+      default:
+        break;
+    }
+  }
+
   /*. Check for aedit stuff -- M. Scott */
   if (OLC_ACTION(d))  {
     switch(cleanup_type)  {
diff -BbuprN tbamud-3.55/src/oasis.h tbamud-3.55+quests/src/oasis.h
--- tbamud-3.55/src/oasis.h	2008-01-16 23:21:16.000000000 +0000
+++ tbamud-3.55+quests/src/oasis.h	2008-01-31 10:18:25.444422000 +0000
@@ -25,7 +25,7 @@
 #define NUM_ATTACK_TYPES	15
 
 #define NUM_ITEM_TYPES		24
-#define NUM_ITEM_FLAGS		17
+#define NUM_ITEM_FLAGS		18
 #define NUM_ITEM_WEARS 		15
 #define NUM_APPLIES		25
 #define NUM_LIQ_TYPES 		16
@@ -101,6 +101,7 @@ struct oasis_olc_data {
   struct zone_data *zone;        /* used for 'zedit'         */
   struct shop_data *shop;        /* used for 'sedit'         */
   struct config_data *config;    /* used for 'cedit'         */
+  struct aq_data *quest;         /* used for 'qedit'         */
   struct extra_descr_data *desc; /* used in '[r|o|m]edit'    */
   struct social_messg *action;   /* Aedit uses this one      */
   struct trig_data *trig;
@@ -130,6 +131,7 @@ extern const char *nrm, *grn, *cyn, *yel
 #define OLC_DESC(d) 	(OLC(d)->desc)		/* Extra description.	*/
 #define OLC_CONFIG(d)	(OLC(d)->config)	/* Config structure.	*/
 #define OLC_TRIG(d)     (OLC(d)->trig)          /* Trigger structure.   */
+#define OLC_QUEST(d)    (OLC(d)->quest)         /* Quest structure      */
 
 #define OLC_ACTION(d)   (OLC(d)->action)        /* Action structure     */
 #define OLC_HELP(d)     (OLC(d)->help)          /* Hedit structure      */
@@ -416,6 +418,8 @@ ACMD(do_oasis_hedit);
 void tedit_string_cleanup(struct descriptor_data *d, int terminator);
 ACMD(do_tedit);
 
+ACMD(do_oasis_qedit);
+
 /* oasis_delete.c */
 int free_strings(void *data, int type);
 
diff -BbuprN tbamud-3.55/src/oasis_list.c tbamud-3.55+quests/src/oasis_list.c
--- tbamud-3.55/src/oasis_list.c	2008-01-16 23:21:16.000000000 +0000
+++ tbamud-3.55+quests/src/oasis_list.c	2008-01-31 12:25:49.335047000 +0000
@@ -21,6 +21,7 @@
 #include "screen.h"
 #include "constants.h"
 #include "dg_scripts.h"
+#include "quest.h"
 
 /* local functions */
 void list_triggers(struct char_data *ch, zone_rnum rnum, trig_vnum vmin, trig_vnum vmax);
@@ -67,6 +68,7 @@ ACMD(do_oasis_list)
     case SCMD_OASIS_RLIST: list_rooms(ch, rzone, vmin, vmax); break;
     case SCMD_OASIS_TLIST: list_triggers(ch, rzone, vmin, vmax); break;
     case SCMD_OASIS_SLIST: list_shops(ch, rzone, vmin, vmax); break;
+    case SCMD_OASIS_QLIST: list_quests(ch, rzone, vmin, vmax); break;
     case SCMD_OASIS_ZLIST:
       if (!*smin)
         list_zones(ch, NOWHERE, 0, zone_table[top_of_zone_table].number);
@@ -349,7 +351,7 @@ void list_zones(struct char_data *ch, zo
 void print_zone(struct char_data *ch, zone_vnum vnum)
 {
   zone_rnum rnum;
-  int size_rooms, size_objects, size_mobiles, i;
+  int size_rooms, size_objects, size_mobiles, size_quests, i;
   room_vnum top, bottom;
   int largest_table;
 
@@ -370,6 +372,7 @@ void print_zone(struct char_data *ch, zo
   size_rooms   = 0;
   size_objects = 0;
   size_mobiles = 0;
+  size_quests  = 0;
   top          = zone_table[rnum].top;
   bottom       = zone_table[rnum].bot;
 
@@ -386,6 +389,7 @@ void print_zone(struct char_data *ch, zo
       if (mob_index[i].vnum >= bottom && mob_index[i].vnum <= top)
         size_mobiles++;
   }
+  size_quests = count_quests(bottom, top);
 
   /* Display all of the zone information at once. */
   send_to_char(ch,
@@ -400,7 +404,8 @@ void print_zone(struct char_data *ch, zo
     "%sSize\r\n"
     "%s   Rooms       = %s%d\r\n"
     "%s   Objects     = %s%d\r\n"
-    "%s   Mobiles     = %s%d%s\r\n",
+    "%s   Mobiles     = %s%d\r\n"
+    "%s   Quests      = %s%d%s\r\n",
     QGRN, QCYN, zone_table[rnum].number,
     QGRN, QCYN, zone_table[rnum].name,
     QGRN, QCYN, zone_table[rnum].builders,
@@ -413,7 +418,8 @@ void print_zone(struct char_data *ch, zo
     QGRN,
     QGRN, QCYN, size_rooms,
     QGRN, QCYN, size_objects,
-    QGRN, QCYN, size_mobiles, QNRM);
+    QGRN, QCYN, size_mobiles,
+    QGRN, QCYN, size_quests, QNRM);
 }
 
 /* List code by Ronald Evers. */
diff -BbuprN tbamud-3.55/src/pfdefaults.h tbamud-3.55+quests/src/pfdefaults.h
--- tbamud-3.55/src/pfdefaults.h	2008-01-16 23:21:16.000000000 +0000
+++ tbamud-3.55+quests/src/pfdefaults.h	2008-01-31 10:23:37.491297000 +0000
@@ -51,6 +51,9 @@
 #define PFDEF_OLC               NOWHERE 
 #define PFDEF_PAGELENGTH        22
 #define PFDEF_QUESTPOINTS       0
+#define PFDEF_QUESTCOUNT        0
+#define PFDEF_COMPQUESTS        0
+#define PFDEF_CURRQUEST         NOTHING
 
 #endif
 
diff -BbuprN tbamud-3.55/src/players.c tbamud-3.55+quests/src/players.c
--- tbamud-3.55/src/players.c	2008-01-16 23:21:14.000000000 +0000
+++ tbamud-3.55+quests/src/players.c	2008-01-31 12:23:52.022547000 +0000
@@ -18,6 +18,7 @@
 #include "dg_scripts.h"
 #include "comm.h"
 #include "interpreter.h"
+#include "quest.h"
 
 #define LOAD_HIT	0
 #define LOAD_MANA	1
@@ -30,6 +31,7 @@ int sprintascii(char *out, bitvector_t b
 void tag_argument(char *argument, char *tag);
 void load_affects(FILE *fl, struct char_data *ch);
 void load_skills(FILE *fl, struct char_data *ch);
+void load_quests(FILE *fl, struct char_data *ch);
 void load_HMVS(struct char_data *ch, const char *line, int mode);
 void write_aliases_ascii(FILE *file, struct char_data *ch);
 void read_aliases_ascii(FILE *file, struct char_data *ch, int count);
@@ -264,6 +266,9 @@ int load_char(const char *name, struct c
     SITTING(ch) = NULL;
     NEXT_SITTING(ch) = NULL;
     GET_QUESTPOINTS(ch) = PFDEF_QUESTPOINTS;
+    GET_QUEST_COUNTER(ch) = PFDEF_QUESTCOUNT;
+    GET_QUEST(ch) = PFDEF_CURRQUEST;
+    GET_NUM_QUESTS(ch) = PFDEF_COMPQUESTS;
 
     for (i = 0; i < AF_ARRAY_MAX; i++)
       AFF_FLAGS(ch)[i] = PFDEF_AFFFLAGS;
@@ -387,6 +392,10 @@ int load_char(const char *name, struct c
 
       case 'Q':
 	     if (!strcmp(tag, "Qstp"))  GET_QUESTPOINTS(ch)     = atoi(line);
+    else if (!strcmp(tag, "Qpnt")) GET_QUESTPOINTS(ch) = atoi(line); /* Backward compatibility */
+    else if (!strcmp(tag, "Qcur")) GET_QUEST(ch) = atoi(line);
+	else if (!strcmp(tag, "Qcnt")) GET_QUEST_COUNTER(ch) = atoi(line);
+	else if (!strcmp(tag, "Qest")) load_quests(fl, ch);
         break;
 
       case 'R':
@@ -599,6 +608,14 @@ void save_char(struct char_data * ch)
   if (GET_OLC_ZONE(ch)     != PFDEF_OLC)        fprintf(fl, "Olc : %d\n", GET_OLC_ZONE(ch));
   if (GET_PAGE_LENGTH(ch)  != PFDEF_PAGELENGTH) fprintf(fl, "Page: %d\n", GET_PAGE_LENGTH(ch));
   if (GET_QUESTPOINTS(ch)  != PFDEF_QUESTPOINTS) fprintf(fl, "Qstp: %d\n", GET_QUESTPOINTS(ch));
+  if (GET_QUEST_COUNTER(ch)!= PFDEF_QUESTCOUNT)  fprintf(fl, "Qcnt: %d\n", GET_QUEST_COUNTER(ch));
+  if (GET_NUM_QUESTS(ch)   != PFDEF_COMPQUESTS) {
+    fprintf(fl, "Qest:\n");
+    for (i = 0; i < GET_NUM_QUESTS(ch); i++)
+      fprintf(fl, "%d\n", ch->player_specials->saved.completed_quests[i]);
+    fprintf(fl, "%d\n", NOTHING);
+  }
+  if (GET_QUEST(ch)        != PFDEF_CURRQUEST)  fprintf(fl, "Qcur: %d\n", GET_QUEST(ch));
 
   /* Save skills */
   if (GET_LEVEL(ch) < LVL_IMMORT) {
@@ -790,6 +807,19 @@ void load_skills(FILE *fl, struct char_d
   } while (num != 0);
 }
 
+void load_quests(FILE *fl, struct char_data *ch)
+{
+  int num = NOTHING;
+  char line[MAX_INPUT_LENGTH + 1];
+
+  do {
+    get_line(fl, line);
+    sscanf(line, "%d", &num);
+    if (num != NOTHING)
+      add_completed_quest(ch, num);
+  } while (num != NOTHING);
+}
+
 void load_HMVS(struct char_data *ch, const char *line, int mode)
 {
   int num = 0, num2 = 0;
diff -BbuprN tbamud-3.55/src/qedit.c tbamud-3.55+quests/src/qedit.c
--- tbamud-3.55/src/qedit.c	1970-01-01 00:00:00.000000000 +0000
+++ tbamud-3.55+quests/src/qedit.c	2008-01-31 12:43:09.647547000 +0000
@@ -0,0 +1,746 @@
+/* ***********************************************************************
+*    File:   qedit.c                                  Part of CircleMUD  *
+* Version:   2.0 (November 2005) Written for CircleMud CWG / Suntzu      *
+* Purpose:   To provide special quest-related code.                      *
+* Copyright: Kenneth Ray                                                 *
+*                                                                        *
+* Made for Oasis OLC                                                     *
+* Copyright 1996 Harvey Gilpin.                                          *
+*********************************************************************** */
+
+#include "conf.h"
+#include "sysdep.h"
+
+#include "structs.h"
+#include "utils.h"
+
+#include "comm.h"
+#include "db.h"
+#include "oasis.h"
+#include "improved-edit.h"
+#include "screen.h"
+#include "genolc.h"
+#include "genzon.h"
+#include "interpreter.h"
+#include "quest.h"
+/*-------------------------------------------------------------------*/
+/* external variables */
+
+extern zone_rnum real_zone_by_thing(room_vnum vznum);
+
+/*-------------------------------------------------------------------*/
+/*. Function prototypes . */
+
+void qedit_setup_new(struct descriptor_data *d);
+void qedit_setup_existing(struct descriptor_data *d, qst_rnum rnum);
+void qedit_parse(struct descriptor_data *d, char *arg);
+void qedit_disp_menu(struct descriptor_data *d);
+void qedit_save_internally(struct descriptor_data *d);
+void qedit_save_to_disk(int num);
+
+/*-------------------------------------------------------------------*/
+
+void qedit_save_internally(struct descriptor_data *d)
+{
+  add_quest(OLC_QUEST(d));
+}
+
+void qedit_save_to_disk(int num)
+{
+  save_quests(num);
+}
+
+/*-------------------------------------------------------------------*\
+  utility functions
+ \*-------------------------------------------------------------------*/
+
+ACMD(do_oasis_qedit)
+{
+  int save = 0;
+  qst_rnum real_num;
+  qst_vnum number = NOWHERE;
+  struct descriptor_data *d;
+  char *buf3;
+  char buf1[MAX_INPUT_LENGTH];
+  char buf2[MAX_INPUT_LENGTH];
+
+  /****************************************************************************/
+  /** Parse any arguments.                                                   **/
+  /****************************************************************************/
+  buf3 = two_arguments(argument, buf1, buf2);
+
+  if (!*buf1) {
+    send_to_char(ch, "Specify a quest VNUM to edit.\r\n");
+    return;
+  } else if (!isdigit(*buf1)) {
+    if (str_cmp("save", buf1) != 0) {
+      send_to_char(ch, "Yikes!  Stop that, someone will get hurt!\r\n");
+      return;
+    }
+
+    save = TRUE;
+
+    if (is_number(buf2))
+      number = atoi(buf2);
+    else if (GET_OLC_ZONE(ch) > 0) {
+      zone_rnum zlok;
+
+      if ((zlok = real_zone(GET_OLC_ZONE(ch))) == NOWHERE)
+        number = NOWHERE;
+      else
+        number = genolc_zone_bottom(zlok);
+    }
+
+    if (number == NOWHERE) {
+      send_to_char(ch, "Save which zone?\r\n");
+      return;
+    }
+  }
+
+  /****************************************************************************/
+  /** If a numeric argument was given, get it.                               **/
+  /****************************************************************************/
+  if (number == NOWHERE)
+    number = atoi(buf1);
+
+  /****************************************************************************/
+  /** Check that the guild isn't already being edited.                       **/
+  /****************************************************************************/
+  for (d = descriptor_list; d; d = d->next) {
+    if (STATE(d) == CON_QEDIT) {
+      if (d->olc && OLC_NUM(d) == number) {
+        send_to_char(ch, "That quest is currently being edited by %s.\r\n",
+          PERS(d->character, ch));
+        return;
+      }
+    }
+  }
+
+  /****************************************************************************/
+  /** Point d to the builder's descriptor.                                   **/
+  /****************************************************************************/
+  d = ch->desc;
+
+  /****************************************************************************/
+  /** Give the descriptor an OLC structure.                                  **/
+  /****************************************************************************/
+  if (d->olc) {
+    mudlog(BRF, LVL_IMMORT, TRUE,
+      "SYSERR: do_oasis_quest: Player already had olc structure.");
+    free(d->olc);
+  }
+
+  CREATE(d->olc, struct oasis_olc_data, 1);
+
+  /****************************************************************************/
+  /** Find the zone.                                                         **/
+  /****************************************************************************/
+  if ((OLC_ZNUM(d) = real_zone_by_thing(number)) == NOWHERE) {
+    send_to_char(ch, "Sorry, there is no zone for that number!\r\n");
+    free(d->olc);
+    d->olc = NULL;
+    return;
+  }
+
+  /****************************************************************************/
+  /** Everyone but IMPLs can only edit zones they have been assigned.        **/
+  /****************************************************************************/
+  if (!can_edit_zone(ch, OLC_ZNUM(d))) {
+    send_to_char(ch, "You do not have permission to edit this zone.\r\n");
+
+    /**************************************************************************/
+    /** Free the OLC structure.                                              **/
+    /**************************************************************************/
+    free(d->olc);
+    d->olc = NULL;
+    return;
+  }
+
+  if (save) {
+    send_to_char(ch, "Saving all quests in zone %d.\r\n",
+      zone_table[OLC_ZNUM(d)].number);
+    mudlog(CMP, MAX(LVL_BUILDER, GET_INVIS_LEV(ch)), TRUE,
+      "OLC: %s saves quest info for zone %d.",
+      GET_NAME(ch), zone_table[OLC_ZNUM(d)].number);
+
+    /**************************************************************************/
+    /** Save the quest to the quest file.                                    **/
+    /**************************************************************************/
+    qedit_save_to_disk(OLC_ZNUM(d));
+
+    /**************************************************************************/
+    /** Free the OLC structure.                                              **/
+    /**************************************************************************/
+    free(d->olc);
+    d->olc = NULL;
+    return;
+  }
+
+  OLC_NUM(d) = number;
+
+  if ((real_num = real_quest(number)) != NOTHING)
+    qedit_setup_existing(d, real_num);
+  else
+    qedit_setup_new(d);
+
+  STATE(d) = CON_QEDIT;
+
+  act("$n starts using OLC.", TRUE, d->character, 0, 0, TO_ROOM);
+  SET_BIT_AR(PLR_FLAGS(ch), PLR_WRITING);
+
+  mudlog(BRF, LVL_IMMORT, TRUE,
+         "OLC: %s starts editing zone %d allowed zone %d",
+         GET_NAME(ch), zone_table[OLC_ZNUM(d)].number, GET_OLC_ZONE(ch));
+}
+
+void qedit_setup_new(struct descriptor_data *d)
+{
+  struct aq_data *quest;
+
+  /* Allociate some quest shaped space                          */
+  CREATE(quest, struct aq_data, 1);
+  /* Set default values                                         */
+  quest->vnum       = OLC_NUM(d);     /* Quest vnum             */
+  quest->qm         = NOBODY;         /* Questmaster rnum       */
+  quest->flags      = 0;              /* Quest bitflags         */
+  quest->type       = AQ_UNDEFINED;   /* Quest type             */
+  quest->target     = NOTHING;        /* Quest target           */
+  quest->prereq     = NOTHING;        /* Prerequisite object    */
+  quest->value[0]   = 0;              /* Points for completing  */
+  quest->value[1]   = 0;              /* Points for abandoning  */
+  quest->value[2]   = 0;              /* Minimum level          */
+  quest->value[3]   = LVL_IMPL;       /* Maximim level          */
+  quest->value[4]   = -1;             /* Time limit             */
+  quest->value[5]   = NOBODY;         /* Mob to return object   */
+  quest->value[6]   = 1;              /* Quantity of targets    */
+  quest->prev_quest = NOTHING;        /* Previous quest         */
+  quest->next_quest = NOTHING;        /* Next quest             */
+  quest->gold_reward= 0;              /* Prize in gold coins    */
+  quest->exp_reward = 0;              /* Prize in exp points    */
+  quest->obj_reward = NOTHING;        /* vnum of reward object  */
+  quest->name       = strdup("Undefined Quest");
+  quest->desc       = strdup("Quest definition is incomplete.");
+  quest->info       = strdup("There is no information on this quest.\r\n");
+  quest->done       = strdup("You have completed the quest.\r\n");
+  quest->quit       = strdup("You have abandoned the quest.\r\n");
+  quest->func       = NULL;           /* Secondary qm spec proc */
+  /* Set the descriptor OLC structure to point to this quest    */
+  OLC_QUEST(d) = quest;
+  /* Show the main quest edit menu                              */
+  qedit_disp_menu(d);
+}
+
+/*-------------------------------------------------------------------*/
+
+void qedit_setup_existing(struct descriptor_data *d, qst_rnum r_num)
+{
+  /*. Alloc some quest shaped space . */
+  CREATE(OLC_QUEST(d), struct aq_data, 1);
+  copy_quest(OLC_QUEST(d), aquest_table + r_num, FALSE);
+  qedit_disp_menu(d);
+}
+
+/*-------------------------------------------------------------------*/
+
+/**************************************************************************
+ Menu functions
+**************************************************************************/
+
+/*-------------------------------------------------------------------*/
+/*. Display main menu . */
+
+void qedit_disp_menu(struct descriptor_data *d)
+{
+  struct aq_data *quest;
+  char quest_flags[MAX_STRING_LENGTH], buf2[MAX_STRING_LENGTH];
+  char targetname[MAX_STRING_LENGTH];
+  mob_vnum return_mob;
+
+  quest = OLC_QUEST(d);
+
+  clear_screen(d);
+  sprintbit(quest->flags, aq_flags, quest_flags, sizeof(quest_flags));
+  if (quest->type == AQ_OBJ_RETURN) {
+    if ((return_mob = real_mobile(quest->value[5])) != NOBODY)
+      snprintf(buf2, sizeof(buf2), "to %s [%d]",
+	       mob_proto[return_mob].player.short_descr,
+	       quest->value[5]);
+    else
+      snprintf(buf2, sizeof(buf2), "to an unknown mob [%d].",
+               quest->value[5]);
+  }
+  switch (quest->type) {
+    case AQ_OBJ_FIND:
+    case AQ_OBJ_RETURN:
+      snprintf(targetname, sizeof(targetname), "%s",
+               real_object(quest->target) == NOTHING ?
+               "An unknown object" :
+               obj_proto[real_object(quest->target)].short_description);
+      break;
+    case AQ_ROOM_FIND:
+    case AQ_ROOM_CLEAR:
+      snprintf(targetname, sizeof(targetname), "%s",
+               real_room(quest->target) == NOWHERE ?
+               "An unknown room" :
+               world[real_room(quest->target)].name);
+      break;
+    case AQ_MOB_FIND:
+    case AQ_MOB_KILL:
+    case AQ_MOB_SAVE:
+      snprintf(targetname, sizeof(targetname), "%s",
+               real_mobile(quest->target) == NOBODY ?
+               "An unknown mobile" :
+               GET_NAME(&mob_proto[real_mobile(quest->target)]));
+      break;
+    default:
+      snprintf(targetname, sizeof(targetname), "Unknown");
+      break;
+  }
+  write_to_output(d,
+    "-- Quest Number    : @n[@c%6d@n]\r\n"
+    "@g 1@n) Quest Name     : @y%s\r\n"
+    "@g 2@n) Description    : @y%s\r\n"
+    "@g 3@n) Accept Message\r\n@y%s"
+    "@g 4@n) Completion Message\r\n@y%s"
+    "@g 5@n) Quit Message\r\n@y%s"
+    "@g 6@n) Quest Flags    : @c%s\r\n"
+    "@g 7@n) Quest Type     : @c%s %s\r\n"
+    "@g 8@n) Quest Master   : [@c%6d@n] @y%s\r\n"
+    "@g 9@n) Quest Target   : [@c%6d@n] @y%s\r\n"
+    "@g A@n) Quantity       : [@c%6d@n]\r\n"
+    "@n    Quest Point Rewards\r\n"
+    "@g B@n) Completed      : [@c%6d@n] @g C@n) Abandoned   : [@c%6d@n]\r\n"
+    "@n    Other Rewards Rewards\r\n"
+    "@g G@n) Gold Coins     : [@c%6d@n] @g T@n) Exp Points  : [@c%6d@n] @g O@n) Object : [@c%6d@n]\r\n"
+    "@n    Level Limits to Accept Quest\r\n"
+    "@g D@n) Lower Level    : [@c%6d@n] @g E@n) Upper Level : [@c%6d@n]\r\n"
+    "@g F@n) Prerequisite   : [@c%6d@n] @y%s\r\n"
+    "@g L@n) Time Limit     : [@c%6d@n]\r\n"
+    "@g N@n) Next Quest     : [@c%6d@n] @y%s\r\n"
+    "@g P@n) Previous Quest : [@c%6d@n] @y%s\r\n"
+    "@g X@n) Delete Quest\r\n"
+    "@g Q@n) Quit\r\n"
+    "Enter Choice : ",
+    quest->vnum,
+    quest->name,
+    quest->desc,
+    quest->info && (str_cmp(quest->info, "undefined"))
+     ? quest->info : "Nothing\r\n",
+    quest->done && (str_cmp(quest->done, "undefined"))
+     ? quest->done : "Nothing\r\n",
+    quest->quit && (str_cmp(quest->quit, "undefined"))
+     ? quest->quit : "Nothing\r\n",
+    quest_flags,
+    quest_types[quest->type],
+    quest->type == AQ_OBJ_RETURN ? buf2 : "",
+    quest->qm == NOBODY ? -1 :     mob_index[quest->qm].vnum,
+    quest->qm == NOBODY ? "none" : mob_proto[quest->qm].player.short_descr,
+    quest->target == NOBODY ? -1 : quest->target, targetname,
+    quest->value[6],
+    quest->value[0], quest->value[1],
+    quest->gold_reward, quest->exp_reward, quest->obj_reward == NOTHING ? -1 : quest->obj_reward,
+    quest->value[2], quest->value[3],
+    quest->prereq     == NOTHING ? -1 : quest->prereq,
+    quest->prereq     == NOTHING ? "" :
+      real_object(quest->prereq) == NOTHING ? "an unknown object" :
+                  obj_proto[real_object(quest->prereq)].short_description,
+    quest->value[4],
+    quest->next_quest == NOTHING ? -1 : quest->next_quest,
+    quest->next_quest == NOTHING ? "" : QST_DESC(real_quest(quest->next_quest)),
+    quest->prev_quest == NOTHING ? -1 : quest->prev_quest,
+    quest->prev_quest == NOTHING ? "" : QST_DESC(real_quest(quest->prev_quest))
+  );
+  OLC_MODE(d) = QEDIT_MAIN_MENU;
+}
+/* For sector type.  */
+void qedit_disp_type_menu(struct descriptor_data *d)
+{
+  int counter, columns = 0;
+
+  clear_screen(d);
+  for (counter = 0; counter < NUM_AQ_TYPES; counter++) {
+    write_to_output(d, "@g%2d@n) %-20.20s %s", counter,
+                quest_types[counter], !(++columns % 2) ? "\r\n" : "");
+  }
+  write_to_output(d, "\r\nEnter Quest type : ");
+  OLC_MODE(d) = QEDIT_TYPES;
+}
+/* For quest flags.  */
+void qedit_disp_flag_menu(struct descriptor_data *d)
+{
+  char bits[MAX_STRING_LENGTH];
+  int counter, columns = 0;
+
+  get_char_colors(d->character);
+  clear_screen(d);
+  for (counter = 0; counter < NUM_AQ_FLAGS; counter++) {
+    write_to_output(d, "%s%2d%s) %-20.20s %s", grn, counter + 1, nrm,
+                aq_flags[counter], !(++columns % 2) ? "\r\n" : "");
+  }
+  sprintbit(OLC_QUEST(d)->flags, aq_flags, bits, sizeof(bits));
+  write_to_output(d, "\r\nQuest flags: @c%s@n\r\n"
+          "Enter quest flags, 0 to quit : ", bits);
+  OLC_MODE(d) = QEDIT_FLAGS;
+}
+/**************************************************************************
+  The GARGANTUAN event handler
+**************************************************************************/
+
+void qedit_parse(struct descriptor_data *d, char *arg)
+{
+  int number = atoi(arg);
+  char *oldtext = NULL;
+
+  switch (OLC_MODE(d)) {
+    /*-------------------------------------------------------------------*/
+    case QEDIT_CONFIRM_SAVESTRING:
+      switch (*arg) {
+        case 'y':
+        case 'Y':
+          send_to_char(d->character, "Saving Quest to memory.\r\n");
+          qedit_save_internally(d);
+          mudlog(CMP, MAX(LVL_BUILDER, GET_INVIS_LEV(d->character)), TRUE,
+	    "OLC: %s edits quest %d", GET_NAME(d->character), OLC_NUM(d));
+          if (CONFIG_OLC_SAVE) {
+            qedit_save_to_disk(real_zone_by_thing(OLC_NUM(d)));
+            write_to_output(d, "Quest %d saved to disk.\r\n", OLC_NUM(d));
+          } else
+            write_to_output(d, "Quest %d saved to memory.\r\n", OLC_NUM(d));
+          cleanup_olc(d, CLEANUP_STRUCTS);
+	  return;
+        case 'n':
+        case 'N':
+          cleanup_olc(d, CLEANUP_ALL);
+          return;
+        default:
+          write_to_output(d,
+            "Invalid choice!\r\nDo you wish to save the quest? : ");
+          return;
+      }
+      break;
+    /*-------------------------------------------------------------------*/
+    case QEDIT_CONFIRM_DELETE:
+      switch (*arg) {
+        case 'y':
+        case 'Y':
+          if (delete_quest(real_quest(OLC_NUM(d))))
+            write_to_output(d, "Quest deleted.\r\n");
+	  else
+            write_to_output(d, "Couldn't delete the quest!\r\n");
+          if (CONFIG_OLC_SAVE) {
+            qedit_save_to_disk(real_zone_by_thing(OLC_NUM(d)));
+            write_to_output(d, "Quest file saved to disk.\r\n");
+          } else
+            write_to_output(d, "Quest file saved to memory.\r\n");
+          cleanup_olc(d, CLEANUP_ALL);
+	  return;
+        case 'n':
+        case 'N':
+          qedit_disp_menu(d);
+          return;
+        default:
+          write_to_output(d,
+            "Invalid choice!\r\nDo you wish to delete the quest? : ");
+          return;
+      }
+      break;
+
+    /*-------------------------------------------------------------------*/
+    case QEDIT_MAIN_MENU:
+      switch (*arg) {
+        case 'q':
+	case 'Q':
+	  if (OLC_VAL(d)) {		/*. Anything been changed? . */
+            write_to_output(d,
+              "Do you wish to save the changes to the Quest? (y/n) : ");
+            OLC_MODE(d) = QEDIT_CONFIRM_SAVESTRING;
+          } else
+            cleanup_olc(d, CLEANUP_ALL);
+          return;
+	case 'x':
+	case 'X':
+          OLC_MODE(d) = QEDIT_CONFIRM_DELETE;
+	  write_to_output(d, "Do you wish to delete the Quest? (y/n) : ");
+	  break;
+	case '1':
+	  OLC_MODE(d) = QEDIT_NAME;
+	  write_to_output(d, "Enter the quest name : ");
+	  break;
+        case '2':
+	  OLC_MODE(d) = QEDIT_DESC;
+	  write_to_output(d, "Enter the quest description :-\r\n] ");
+	  break;
+        case '3':
+          OLC_MODE(d) = QEDIT_INFO;
+          clear_screen(d);
+          send_editor_help(d);
+          write_to_output(d, "Enter quest acceptance message:\r\n\r\n");
+
+          if (OLC_QUEST(d)->info) {
+            write_to_output(d, "%s", OLC_QUEST(d)->info);
+            oldtext = strdup(OLC_QUEST(d)->info);
+          }
+          string_write(d, &OLC_QUEST(d)->info, MAX_QUEST_MSG, 0, oldtext);
+          OLC_VAL(d) = 1;
+          break;
+        case '4':
+          OLC_MODE(d) = QEDIT_COMPLETE;
+          clear_screen(d);
+          send_editor_help(d);
+          write_to_output(d, "Enter quest completion message:\r\n\r\n");
+
+          if (OLC_QUEST(d)->done) {
+            write_to_output(d, "%s", OLC_QUEST(d)->done);
+            oldtext = strdup(OLC_QUEST(d)->done);
+          }
+          string_write(d, &OLC_QUEST(d)->done, MAX_QUEST_MSG, 0, oldtext);
+          OLC_VAL(d) = 1;
+          break;
+        case '5':
+          OLC_MODE(d) = QEDIT_ABANDON;
+          clear_screen(d);
+          send_editor_help(d);
+          write_to_output(d, "Enter quest quit message:\r\n\r\n");
+
+          if (OLC_QUEST(d)->quit) {
+            write_to_output(d, "%s", OLC_QUEST(d)->quit);
+            oldtext = strdup(OLC_QUEST(d)->quit);
+          }
+          string_write(d, &OLC_QUEST(d)->quit, MAX_QUEST_MSG, 0, oldtext);
+          OLC_VAL(d) = 1;
+          break;
+        case '6':
+          OLC_MODE(d) = QEDIT_FLAGS;
+          qedit_disp_flag_menu(d);
+          break;
+        case '7':
+          OLC_MODE(d) = QEDIT_TYPES;
+          qedit_disp_type_menu(d);
+          break;
+        case '8':
+          OLC_MODE(d) = QEDIT_QUESTMASTER;
+          write_to_output(d, "Enter vnum of quest master : ");
+          break;
+        case '9':
+          OLC_MODE(d) = QEDIT_TARGET;
+          write_to_output(d, "Enter target vnum : ");
+          break;
+	case 'a':
+	case 'A':
+	  OLC_MODE(d) = QEDIT_QUANTITY;
+	  write_to_output(d, "Enter quantity of target : ");
+	  break;
+        case 'b':
+        case 'B':
+	  OLC_MODE(d) = QEDIT_POINTSCOMP;
+          write_to_output(d, "Enter points for completing the quest : " );
+          break;
+	case 'c':
+        case 'C':
+	  OLC_MODE(d) = QEDIT_POINTSQUIT;
+          write_to_output(d, "Enter points for quitting the quest : " );
+          break;
+	case 'd':
+        case 'D':
+	  OLC_MODE(d) = QEDIT_LEVELMIN;
+          write_to_output(d, "Enter minimum level to accept the quest : " );
+          break;
+	case 'e':
+        case 'E':
+	  OLC_MODE(d) = QEDIT_LEVELMAX;
+          write_to_output(d, "Enter maximum level to accept the quest : " );
+          break;
+	case 'f':
+	case 'F':
+	  OLC_MODE(d) = QEDIT_PREREQ;
+	  write_to_output(d, "Enter a prerequisite object vnum (-1 for none) : ");
+	  break;
+	case 'g':
+	case 'G':
+	  OLC_MODE(d) = QEDIT_GOLD;
+	  write_to_output(d, "Enter the number of gold coins (0 for none) : ");
+	  break;
+	case 't':
+	case 'T':
+	  OLC_MODE(d) = QEDIT_EXP;
+	  write_to_output(d, "Enter a number of experience points (0 for none) : ");
+	  break;
+	case 'o':
+	case 'O':
+	  OLC_MODE(d) = QEDIT_OBJ;
+	  write_to_output(d, "Enter the prize object vnum (-1 for none) : ");
+	  break;
+	case 'l':
+        case 'L':
+	  OLC_MODE(d) = QEDIT_TIMELIMIT;
+          write_to_output(d, "Enter time limit to complete (-1 for none) : " );
+          break;
+	case 'n':
+	case 'N':
+          OLC_MODE(d) = QEDIT_NEXTQUEST;
+          write_to_output(d, "Enter vnum of next quest (-1 for none) : ");
+          break;
+ 	case 'p':
+	case 'P':
+          OLC_MODE(d) = QEDIT_PREVQUEST;
+          write_to_output(d, "Enter vnum of previous quest (-1 for none) : ");
+          break;
+        default:
+	  write_to_output(d, "Invalid chioce!");
+	  qedit_disp_menu(d);
+	  break;
+      }
+      return;
+    /*-------------------------------------------------------------------*/
+    case QEDIT_NAME:
+      if (!genolc_checkstring(d, arg))
+        break;
+      if (OLC_QUEST(d)->name)
+        free(OLC_QUEST(d)->name);
+      arg[MAX_QUEST_NAME - 1] = '\0';
+      OLC_QUEST(d)->name = str_udup(arg);
+      break;
+    case QEDIT_DESC:
+      if (!genolc_checkstring(d, arg))
+        break;
+      if (OLC_QUEST(d)->desc)
+        free(OLC_QUEST(d)->desc);
+      arg[MAX_QUEST_DESC - 1] = '\0';
+      OLC_QUEST(d)->desc = str_udup(arg);
+      break;
+    case QEDIT_QUESTMASTER:
+      if (number != -1)
+        if ((number = real_mobile(number)) == NOBODY) {
+          write_to_output(d, "That mobile does not exist, try again : ");
+          return;
+        }
+      OLC_QUEST(d)->qm = number;
+      break;
+    case QEDIT_TYPES:
+      if (number < 0 || number >= NUM_AQ_TYPES) {
+        write_to_output(d, "Invalid choice!\r\n");
+        qedit_disp_type_menu(d);
+        return;
+      }
+      OLC_QUEST(d)->type = number;
+      if (number == AQ_OBJ_RETURN) {
+        OLC_MODE(d) = QEDIT_RETURNMOB;
+        write_to_output(d, "Enter mob vnum to return object to : ");
+        return;
+      }
+      break;
+    case QEDIT_FLAGS:
+      if (number < 0 || number > NUM_AQ_FLAGS) {
+        write_to_output(d, "That is not a valid choice!\r\n");
+        qedit_disp_flag_menu(d);
+      } else if (number == 0)
+        break;
+      else {
+        TOGGLE_BIT(OLC_QUEST(d)->flags, number );
+        qedit_disp_flag_menu(d);
+      }
+      return;
+    case QEDIT_QUANTITY:
+      OLC_QUEST(d)->value[6] = LIMIT(number, 1, 50);
+      break;
+    case QEDIT_POINTSCOMP:
+      OLC_QUEST(d)->value[0] = LIMIT(number, 0, 999999);
+      break;
+    case QEDIT_POINTSQUIT:
+      OLC_QUEST(d)->value[1] = LIMIT(number, 0, 999999);
+      break;
+    case QEDIT_PREREQ:
+      if ((number = atoi(arg)) != -1)
+        if (real_object(number) == NOTHING) {
+          write_to_output(d, "That object does not exist, try again : ");
+          return;
+        }
+      OLC_QUEST(d)->prereq = number;
+      break;
+    case QEDIT_LEVELMIN:
+      if (number < 0 || number > LVL_IMPL) {
+        write_to_output(d, "Level must be between 0 and %d!\r\n", LVL_IMPL);
+	write_to_output(d, "Enter minimum level to accept the quest : " );
+        return;
+      }	else if (number > OLC_QUEST(d)->value[3]) {
+	write_to_output(d, "Minimum level can't be above maximum level!\r\n");
+	write_to_output(d, "Enter minimum level to accept the quest : " );
+        return;
+      } else {
+        OLC_QUEST(d)->value[2] = number;
+        break;
+      }
+    case QEDIT_LEVELMAX:
+      if (number < 0 || number > LVL_IMPL) {
+        write_to_output(d, "Level must be between 0 and %d!\r\n", LVL_IMPL);
+	write_to_output(d, "Enter maximum level to accept the quest : " );
+        return;
+      } else if (number < OLC_QUEST(d)->value[2]) {
+	write_to_output(d, "Maximum level can't be below minimum level!\r\n");
+	write_to_output(d, "Enter maximum level to accept the quest : " );
+        return;
+      } else {
+        OLC_QUEST(d)->value[3] = number;
+        break;
+      }
+    case QEDIT_TIMELIMIT:
+      OLC_QUEST(d)->value[4] = LIMIT(number, -1, 100);
+      break;
+    case QEDIT_RETURNMOB:
+      if ((number = atoi(arg)) != -1)
+        if (real_mobile(number) == NOBODY) {
+          write_to_output(d, "That mobile does not exist, try again : ");
+          return;
+        }
+      OLC_QUEST(d)->value[5] = number;
+      break;
+    case QEDIT_TARGET:
+      OLC_QUEST(d)->target = number;
+      break;
+    case QEDIT_NEXTQUEST:
+      OLC_QUEST(d)->next_quest = (number == -1 ? NOTHING : atoi(arg));
+      break;
+    case QEDIT_PREVQUEST:
+      OLC_QUEST(d)->prev_quest = (number == -1 ? NOTHING : atoi(arg));
+      break;
+    case QEDIT_GOLD:
+      OLC_QUEST(d)->gold_reward = LIMIT(number, 0, 99999);
+      break;
+    case QEDIT_EXP:
+      OLC_QUEST(d)->exp_reward = LIMIT(number, 0, 99999);
+      break;
+    case QEDIT_OBJ:
+      if ((number = atoi(arg)) != -1)
+        if (real_object(number) == NOTHING) {
+          write_to_output(d, "That object does not exist, try again : ");
+          return;
+        }
+      OLC_QUEST(d)->obj_reward = number;
+      break;
+    default:
+      /*. We should never get here . */
+      cleanup_olc(d, CLEANUP_ALL);
+      mudlog(BRF, LVL_BUILDER, TRUE, "SYSERR: OLC: qedit_parse(): "
+				 "Reached default case!");
+      write_to_output(d, "Oops...\r\n");
+      break;
+  }
+  /*-------------------------------------------------------------------*/
+  /*. END OF CASE
+  If we get here, we have probably changed something, and now want to
+  return to main menu.  Use OLC_VAL as a 'has changed' flag . */
+
+  OLC_VAL(d) = 1;
+  qedit_disp_menu(d);
+}
+
+void qedit_string_cleanup(struct descriptor_data *d, int terminator)
+{
+  switch (OLC_MODE(d)) {
+  case QEDIT_INFO:
+  case QEDIT_COMPLETE:
+  case QEDIT_ABANDON:
+    qedit_disp_menu(d);
+    break;
+  }
+}
diff -BbuprN tbamud-3.55/src/quest.c tbamud-3.55+quests/src/quest.c
--- tbamud-3.55/src/quest.c	1970-01-01 00:00:00.000000000 +0000
+++ tbamud-3.55+quests/src/quest.c	2008-01-31 12:30:49.022547000 +0000
@@ -0,0 +1,796 @@
+/* ***********************************************************************
+*    File:   quest.c                                  Part of CircleMUD  *
+* Version:   2.1 (December 2005) Written for CircleMud CWG / Suntzu      *
+* Purpose:   To provide special quest-related code.                      *
+* Copyright: Kenneth Ray                                                 *
+* Original Version Details:                                              *
+* Morgaelin - quest.c                                                    *
+* Copyright (C) 1997 MS                                                  *
+*********************************************************************** */
+#include "conf.h"
+#include "sysdep.h"
+
+#include "structs.h"
+#include "utils.h"
+#include "interpreter.h"
+#include "handler.h"
+#include "db.h"
+#include "comm.h"
+#include "screen.h"
+#include "quest.h"
+
+/* External Functions */
+ACMD(do_tell);
+extern struct index_data *mob_index;
+extern struct index_data *obj_index;
+extern struct room_data *world;
+extern long asciiflag_conv(char *flag);
+/* Local Variables */
+int cmd_tell;
+const char *quest_types[] = {
+  "Object",
+  "Room",
+  "Find mob",
+  "Kill mob",
+  "Save mob",
+  "Return object",
+  "Clear room",
+  "\n"
+};
+const char *aq_flags[] = {
+  "REPEATABLE",
+  "\n"
+};
+const char *quest_cmd[] = {
+  "list", "history", "join", "leave", "progress", "status", "\n"};
+const char *quest_mort_usage =
+  "Usage: quest list | history | progress | join <nn> | leave";
+const char *quest_imm_usage =
+  "Usage: quest list | history | progress | join <nn> | leave | status <vnum>";
+
+/*--------------------------------------------------------------------------*/
+/* Utility Functions                                                        */
+/*--------------------------------------------------------------------------*/
+
+qst_rnum real_quest(qst_vnum vnum)
+{
+  int rnum;
+
+  for (rnum = 0; rnum < total_quests; rnum++)
+    if (QST_NUM(rnum) == vnum)
+      return(rnum);
+  return(NOTHING);
+}
+
+int is_complete(struct char_data *ch, qst_vnum vnum)
+{
+  int i;
+
+  for (i = 0; i < GET_NUM_QUESTS(ch); i++)
+    if (ch->player_specials->saved.completed_quests[i] == vnum)
+      return TRUE;
+  return FALSE;
+}
+
+qst_vnum find_quest_by_qmnum(struct char_data *ch, mob_rnum qm, int num)
+{
+  qst_rnum rnum;
+  int found=0;
+  for (rnum = 0; rnum < total_quests; rnum++) {
+    if (qm == QST_MASTER(rnum))
+      if (++found == num)
+        return (QST_NUM(rnum));
+  }
+  return NOTHING;
+}
+
+/*--------------------------------------------------------------------------*/
+/* Quest Loading and Unloading Functions                                    */
+/*--------------------------------------------------------------------------*/
+
+void destroy_quests(void)
+{
+  qst_rnum rnum = 0;
+
+  if (!aquest_table)
+    return;
+
+  for (rnum = 0; rnum < total_quests; rnum++){
+    free_quest_strings(&aquest_table[rnum]);
+  }
+  free(aquest_table);
+  aquest_table = NULL;
+  total_quests = 0;
+
+  return;
+}
+
+int count_quests(qst_vnum low, qst_vnum high)
+{
+  int i, j;
+
+  for (i = j = 0; QST_NUM(i) <= high; i++)
+    if (QST_NUM(i) >= low)
+      j++;
+
+  return j;
+}
+
+void parse_quest(FILE *quest_f, int nr)
+{
+  static char line[256];
+  static int i = 0, j;
+  int retval = 0, t[7];
+  char f1[128], buf2[MAX_STRING_LENGTH];
+  aquest_table[i].vnum = nr;
+  aquest_table[i].qm = NOBODY;
+  aquest_table[i].name = NULL;
+  aquest_table[i].desc = NULL;
+  aquest_table[i].info = NULL;
+  aquest_table[i].done = NULL;
+  aquest_table[i].quit = NULL;
+  aquest_table[i].flags = 0;
+  aquest_table[i].type = -1;
+  aquest_table[i].target = -1;
+  aquest_table[i].prereq = NOTHING;
+  for (j = 0; j < 7; j++)
+    aquest_table[i].value[j] = 0;
+  aquest_table[i].prev_quest = NOTHING;
+  aquest_table[i].next_quest = NOTHING;
+  aquest_table[i].func = NULL;
+
+  aquest_table[i].gold_reward = 0;
+  aquest_table[i].exp_reward  = 0;
+  aquest_table[i].obj_reward  = NOTHING;
+
+  /* begin to parse the data */
+  aquest_table[i].name = fread_string(quest_f, buf2);
+  aquest_table[i].desc = fread_string(quest_f, buf2);
+  aquest_table[i].info = fread_string(quest_f, buf2);
+  aquest_table[i].done = fread_string(quest_f, buf2);
+  aquest_table[i].quit = fread_string(quest_f, buf2);
+  if (!get_line(quest_f, line) ||
+      (retval = sscanf(line, " %d %d %s %d %d %d %d",
+             t, t+1, f1, t+2, t+3, t + 4, t + 5)) != 7) {
+    log("Format error in numeric line (expected 7, got %d), %s\n",
+        retval, line);
+    exit(1);
+  }
+  aquest_table[i].type       = t[0];
+  aquest_table[i].qm         = real_mobile(t[1]);
+  aquest_table[i].flags      = asciiflag_conv(f1);
+  aquest_table[i].target     = (t[2] == -1) ? NOTHING : t[2];
+  aquest_table[i].prev_quest = (t[3] == -1) ? NOTHING : t[3];
+  aquest_table[i].next_quest = (t[4] == -1) ? NOTHING : t[4];
+  aquest_table[i].prereq     = (t[5] == -1) ? NOTHING : t[5];
+  if (!get_line(quest_f, line) ||
+      (retval = sscanf(line, " %d %d %d %d %d %d %d",
+		       t, t+1, t+2, t+3, t+4, t + 5, t + 6)) != 7) {
+    log("Format error in numeric line (expected 7, got %d), %s\n",
+        retval, line);
+    exit(1);
+  }
+  for (j = 0; j < 7; j++)
+    aquest_table[i].value[j] = t[j];
+
+  if (!get_line(quest_f, line) ||
+      (retval = sscanf(line, " %d %d %d",
+             t, t+1, t+2)) != 3) {
+    log("Format error in numeric (rewards) line (expected 3, got %d), %s\n",
+        retval, line);
+    exit(1);
+  }
+
+  aquest_table[i].gold_reward = t[0];
+  aquest_table[i].exp_reward  = t[1];
+  aquest_table[i].obj_reward  = (t[2] == -1) ? NOTHING : t[2];
+
+  for (;;) {
+    if (!get_line(quest_f, line)) {
+      log("Format error in %s\n", line);
+      exit(1);
+    }
+    switch(*line) {
+    case 'S':
+      total_quests = ++i;
+      return;
+      break;
+    }
+  }
+} /* parse_quest */
+
+void assign_the_quests(void)
+{
+  qst_rnum rnum;
+
+  cmd_tell = find_command("tell");
+
+  for (rnum = 0; rnum < total_quests; rnum ++) {
+    if (QST_MASTER(rnum) == NOBODY) {
+      log("SYSERR: Quest #%d has no questmaster specified.", QST_NUM(rnum));
+      continue;
+    }
+    if (mob_index[QST_MASTER(rnum)].func &&
+	mob_index[QST_MASTER(rnum)].func != questmaster)
+      QST_FUNC(rnum) = mob_index[QST_MASTER(rnum)].func;
+    mob_index[QST_MASTER(rnum)].func = questmaster;
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+/* Quest Completion Functions                                               */
+/*--------------------------------------------------------------------------*/
+void set_quest(struct char_data *ch, qst_rnum rnum)
+{
+  GET_QUEST(ch) = QST_NUM(rnum);
+  GET_QUEST_TIME(ch) = QST_TIME(rnum);
+  GET_QUEST_COUNTER(ch) = QST_QUANTITY(rnum);
+  SET_BIT_AR(PRF_FLAGS(ch), PRF_QUEST);
+  return;
+}
+
+void clear_quest(struct char_data *ch)
+{
+  GET_QUEST(ch) = NOTHING;
+  GET_QUEST_TIME(ch) = -1;
+  GET_QUEST_COUNTER(ch) = 0;
+  REMOVE_BIT_AR(PRF_FLAGS(ch), PRF_QUEST);
+  return;
+}
+
+void add_completed_quest(struct char_data *ch, qst_vnum vnum)
+{
+  qst_vnum *temp;
+  int i;
+
+  CREATE(temp, qst_vnum, GET_NUM_QUESTS(ch) +1);
+  for (i=0; i < GET_NUM_QUESTS(ch); i++)
+    temp[i] = ch->player_specials->saved.completed_quests[i];
+
+  temp[GET_NUM_QUESTS(ch)] = vnum;
+  GET_NUM_QUESTS(ch)++;
+
+  if (ch->player_specials->saved.completed_quests)
+    free(ch->player_specials->saved.completed_quests);
+  ch->player_specials->saved.completed_quests = temp;
+}
+
+void remove_completed_quest(struct char_data *ch, qst_vnum vnum)
+{
+  qst_vnum *temp;
+  int i, j = 0;
+
+  CREATE(temp, qst_vnum, GET_NUM_QUESTS(ch));
+  for (i = 0; i < GET_NUM_QUESTS(ch); i++)
+    if (ch->player_specials->saved.completed_quests[i] != vnum)
+      temp[j++] = ch->player_specials->saved.completed_quests[i];
+
+  GET_NUM_QUESTS(ch)--;
+
+  if (ch->player_specials->saved.completed_quests)
+    free(ch->player_specials->saved.completed_quests);
+  ch->player_specials->saved.completed_quests = temp;
+}
+
+void generic_complete_quest(struct char_data *ch)
+{
+  qst_rnum rnum;
+  qst_vnum vnum = GET_QUEST(ch);
+  struct obj_data *new_obj;
+
+  if (--GET_QUEST_COUNTER(ch) <= 0) {
+    rnum = real_quest(vnum);
+    GET_QUESTPOINTS(ch) += QST_POINTS(rnum);
+    send_to_char(ch,
+          "%s\r\nYou have been awarded %d quest points for your service.\r\n",
+          QST_DONE(rnum), QST_POINTS(rnum));
+    if (QST_GOLD(rnum)) {
+      GET_GOLD(ch) += QST_GOLD(rnum);
+      send_to_char(ch,
+            "You have been awarded %d gold coins for your service.\r\n",
+            QST_GOLD(rnum));
+    }
+    if (QST_EXP(rnum)) {
+      gain_exp(ch, QST_GOLD(rnum));
+      send_to_char(ch,
+            "You have been awarded %d experience points for your service.\r\n",
+            QST_EXP(rnum));
+    }
+    if (QST_OBJ(rnum)) {
+      if (real_object(QST_OBJ(rnum))) {
+		if ((new_obj = create_obj()) != NULL) {
+          new_obj = read_object((QST_OBJ(rnum)),VIRTUAL);
+          obj_to_char(new_obj, ch);
+          send_to_char(ch,
+                "You have been presented with %s%s for your service.\r\n",
+                GET_OBJ_SHORT(new_obj), CCNRM(ch, C_NRM));
+        }
+      }
+    }
+    if (!IS_SET(QST_FLAGS(rnum), AQ_REPEATABLE))
+      add_completed_quest(ch, vnum);
+    clear_quest(ch);
+    if ((real_quest(QST_NEXT(rnum)) != NOTHING) &&
+        (QST_NEXT(rnum) != vnum) &&
+        !is_complete(ch, QST_NEXT(rnum))) {
+      rnum = real_quest(QST_NEXT(rnum));
+      set_quest(ch, rnum);
+      send_to_char(ch,
+          "The next stage of your quest awaits:\r\n%s",
+          QST_INFO(rnum));
+    }
+  }
+  save_char(ch);
+}
+
+void autoquest_trigger_check(struct char_data *ch, struct char_data *vict,
+		             struct obj_data *object, int type)
+{
+  struct char_data *i;
+  qst_rnum rnum;
+  int found = TRUE;
+
+  if (IS_NPC(ch))
+    return;
+  if (GET_QUEST(ch) == NOTHING)  /* No current quest, skip this */
+    return;
+  if (GET_QUEST_TYPE(ch) != type)
+    return;
+  if ((rnum = real_quest(GET_QUEST(ch))) == NOTHING)
+    return;
+  switch (type) {
+    case AQ_OBJ_FIND:
+      if (QST_TARGET(rnum) == GET_OBJ_VNUM(object))
+        generic_complete_quest(ch);
+      break;
+    case AQ_ROOM_FIND:
+      if (QST_TARGET(rnum) == world[IN_ROOM(ch)].number)
+        generic_complete_quest(ch);
+      break;
+    case AQ_MOB_FIND:
+      for (i=world[IN_ROOM(ch)].people; i; i = i->next_in_room)
+        if (IS_NPC(i))
+          if (QST_TARGET(rnum) == GET_MOB_VNUM(i))
+            generic_complete_quest(ch);
+      break;
+    case AQ_MOB_KILL:
+      if (!IS_NPC(ch) && IS_NPC(vict) && (ch != vict))
+          if (QST_TARGET(rnum) == GET_MOB_VNUM(vict))
+            generic_complete_quest(ch);
+      break;
+    case AQ_MOB_SAVE:
+       if (ch == vict)
+        found = FALSE;
+      for (i = world[IN_ROOM(ch)].people; i && found; i = i->next_in_room)
+          if (i && IS_NPC(i) && !MOB_FLAGGED(i, MOB_NOTDEADYET))
+            if ((GET_MOB_VNUM(i) != QST_TARGET(rnum)) &&
+                !AFF_FLAGGED(i, AFF_CHARM))
+              found = FALSE;
+      if (found)
+        generic_complete_quest(ch);
+      break;
+    case AQ_OBJ_RETURN:
+      if (IS_NPC(vict) && (GET_MOB_VNUM(vict) == QST_RETURNMOB(rnum)))
+        if (object && (GET_OBJ_VNUM(object) == QST_TARGET(rnum)))
+          generic_complete_quest(ch);
+      break;
+    case AQ_ROOM_CLEAR:
+      if (QST_TARGET(rnum) == world[IN_ROOM(ch)].number) {
+        for (i = world[IN_ROOM(ch)].people; i && found; i = i->next_in_room)
+          if (i && IS_NPC(i) && !MOB_FLAGGED(i, MOB_NOTDEADYET))
+            found = FALSE;
+        if (found)
+	  generic_complete_quest(ch);
+      }
+      break;
+    default:
+      log("SYSERR: Invalid quest type passed to autoquest_trigger_check");
+      break;
+  }
+}
+
+void quest_timeout(struct char_data *ch)
+{
+  if ((GET_QUEST(ch) != NOTHING) && (GET_QUEST_TIME(ch) != -1)) {
+    clear_quest(ch);
+    send_to_char(ch, "You have run out of time to complete the quest.\r\n");
+  }
+}
+
+void check_timed_quests(void)
+{
+  struct char_data *ch;
+
+  for (ch = character_list; ch; ch = ch->next)
+    if ((GET_QUEST(ch) != NOTHING) && (GET_QUEST_TIME(ch) != -1))
+      if (--GET_QUEST_TIME(ch) == 0)
+        quest_timeout(ch);
+}
+
+/*--------------------------------------------------------------------------*/
+/* Quest Command Helper Functions                                           */
+/*--------------------------------------------------------------------------*/
+
+void list_quests(struct char_data *ch, zone_rnum zone, qst_vnum vmin, qst_vnum vmax)
+{
+  qst_rnum rnum;
+  qst_vnum bottom, top;
+  int counter = 0;
+
+  if (zone != NOWHERE) {
+    bottom = zone_table[zone].bot;
+    top    = zone_table[zone].top;
+  } else {
+    bottom = vmin;
+    top    = vmax;
+  }
+  /* Print the header for the quest listing. */
+  send_to_char (ch,
+  "Index VNum    Description                                  Questmaster\r\n"
+  "----- ------- -------------------------------------------- -----------\r\n");
+  for (rnum = 0; rnum < total_quests ; rnum++)
+    if (QST_NUM(rnum) >= bottom && QST_NUM(rnum) <= top)
+      send_to_char(ch, "@g%4d@n) [@g%-5d@n] @c%-44.44s@n @y[%5d]@n\r\n",
+                   ++counter,
+                   QST_NUM(rnum), QST_NAME(rnum),
+                   mob_index[QST_MASTER(rnum)].vnum);
+  if (!counter)
+    send_to_char(ch, "None found.\r\n");
+}
+
+void quest_hist(struct char_data *ch)
+{
+  int i = 0, counter = 0;
+  qst_rnum rnum = NOTHING;
+
+  send_to_char(ch, "Quests that you have completed:\r\n"
+    "Index Description                                          Questmaster\r\n"
+    "----- ---------------------------------------------------- -----------\r\n");
+  for (i = 0; i < GET_NUM_QUESTS(ch); i++) {
+    if ((rnum = real_quest(ch->player_specials->saved.completed_quests[i])) != NOTHING)
+      send_to_char(ch, "@g%4d@n) @c%-52.52s@n @y%s@n\r\n",
+	++counter, QST_DESC(rnum), GET_NAME(&mob_proto[QST_MASTER(rnum)]));
+    else
+      send_to_char(ch,
+        "@g%4d@n) @cUnknown Quest (it no longer exists)@n\r\n", ++counter);
+  }
+  if (!counter)
+    send_to_char(ch, "You haven't completed any quests yet.\r\n");
+}
+
+void quest_join(struct char_data *ch, struct char_data *qm, char argument[MAX_INPUT_LENGTH])
+{
+  qst_vnum vnum;
+  qst_rnum rnum;
+  char buf[MAX_INPUT_LENGTH];
+
+  if (!*argument)
+    snprintf(buf, sizeof(buf),
+             "%s What quest did you wish to join?", GET_NAME(ch));
+  else if (GET_QUEST(ch) != NOTHING)
+    snprintf(buf, sizeof(buf),
+             "%s But you are already part of a quest!", GET_NAME(ch));
+  else if((vnum = find_quest_by_qmnum(ch, qm->nr, atoi(argument))) == NOTHING)
+    snprintf(buf, sizeof(buf),
+             "%s I don't know of such a quest!", GET_NAME(ch));
+  else if ((rnum = real_quest(vnum)) == NOTHING)
+    snprintf(buf, sizeof(buf),
+             "%s I don't know of such a quest!", GET_NAME(ch));
+  else if (GET_LEVEL(ch) < QST_MINLEVEL(rnum))
+    snprintf(buf, sizeof(buf),
+             "%s You are not experienced enough for that quest!", GET_NAME(ch));
+  else if (GET_LEVEL(ch) > QST_MAXLEVEL(rnum))
+    snprintf(buf, sizeof(buf),
+             "%s You are too experienced for that quest!", GET_NAME(ch));
+  else if (is_complete(ch, vnum))
+    snprintf(buf, sizeof(buf),
+             "%s You have already completed that quest!", GET_NAME(ch));
+  else if ((QST_PREV(rnum) != NOTHING) && !is_complete(ch, vnum))
+    snprintf(buf, sizeof(buf),
+             "%s That quest is not available to you yet!", GET_NAME(ch));
+  else if ((QST_PREREQ(rnum) != NOTHING) &&
+           (real_object(QST_PREREQ(rnum)) != NOTHING) &&
+           (get_obj_in_list_num(real_object(QST_PREREQ(rnum)),
+				ch->carrying) == NULL))
+    snprintf(buf, sizeof(buf),
+             "%s You need to have %s first!", GET_NAME(ch),
+	     obj_proto[real_object(QST_PREREQ(rnum))].short_description);
+  else {
+    act("You join the quest.",    TRUE, ch, NULL, NULL, TO_CHAR);
+    act("$n has joined a quest.", TRUE, ch, NULL, NULL, TO_ROOM);
+    snprintf(buf, sizeof(buf),
+             "%s Listen carefully to the instructions.", GET_NAME(ch));
+    do_tell(qm, buf, cmd_tell, 0);
+    set_quest(ch, rnum);
+    send_to_char(ch, QST_INFO(rnum));
+    if (QST_TIME(rnum) != -1)
+      snprintf(buf, sizeof(buf),
+        "%s You have a time limit of %d turn%s to complete the quest.",
+        GET_NAME(ch), QST_TIME(rnum), QST_TIME(rnum) == 1 ? "" : "s");
+    else
+      snprintf(buf, sizeof(buf),
+        "%s You can take however long you want to complete the quest.",
+	GET_NAME(ch));
+  }
+  do_tell(qm, buf, cmd_tell, 0);
+  save_char(ch);
+}
+
+void quest_list(struct char_data *ch, struct char_data *qm, char argument[MAX_INPUT_LENGTH])
+{
+  qst_vnum vnum;
+  qst_rnum rnum;
+
+  if ((vnum = find_quest_by_qmnum(ch, qm->nr, atoi(argument))) == NOTHING)
+    send_to_char(ch, "That is not a valid quest!\r\n");
+  else if ((rnum = real_quest(vnum)) == NOTHING)
+    send_to_char(ch, "That is not a valid quest!\r\n");
+  else if (QST_INFO(rnum)) {
+    send_to_char(ch,"Complete Details on Quest %d @c%s@n:\r\n%s",
+                      vnum,
+		      QST_DESC(rnum),
+		      QST_INFO(rnum));
+    if (QST_PREV(rnum) != NOTHING)
+      send_to_char(ch, "You have to have completed quest %s first.\r\n",
+          QST_NAME(real_quest(QST_PREV(rnum))));
+    if (QST_TIME(rnum) != -1)
+      send_to_char(ch,
+         "There is a time limit of %d turn%s to complete the quest.\r\n",
+          QST_TIME(rnum),
+          QST_TIME(rnum) == 1 ? "" : "s");
+  } else
+    send_to_char(ch, "There is no further information on that quest.\r\n");
+}
+
+void quest_quit(struct char_data *ch)
+{
+  qst_rnum rnum;
+
+  if (GET_QUEST(ch) == NOTHING)
+    send_to_char(ch, "But you currently aren't on a quest!\r\n");
+  else if ((rnum = real_quest(GET_QUEST(ch))) == NOTHING) {
+    clear_quest(ch);
+    send_to_char(ch, "You are now no longer part of the quest.\r\n");
+    save_char(ch);
+  } else {
+    clear_quest(ch);
+    if (QST_QUIT(rnum) && (str_cmp(QST_QUIT(rnum), "undefined") != 0))
+      send_to_char(ch, "%s", QST_QUIT(rnum));
+    else
+      send_to_char(ch, "You are now no longer part of the quest.\r\n");
+    if (QST_PENALTY(rnum)) {
+      GET_QUESTPOINTS(ch) -= QST_PENALTY(rnum);
+      send_to_char(ch,
+        "You have lost %d quest points for your cowardice.\r\n",
+        QST_PENALTY(rnum));
+    }
+    save_char(ch);
+  }
+}
+
+void quest_progress(struct char_data *ch)
+{
+  qst_rnum rnum;
+
+  if (GET_QUEST(ch) == NOTHING)
+    send_to_char(ch, "But you currently aren't on a quest!\r\n");
+  else if ((rnum = real_quest(GET_QUEST(ch))) == NOTHING) {
+    clear_quest(ch);
+    send_to_char(ch, "Your quest seems to no longer exist.\r\n");
+  } else {
+    send_to_char(ch, "You are on the following quest:\r\n%s\r\n%s",
+		     QST_DESC(rnum), QST_INFO(rnum));
+    if (QST_QUANTITY(rnum) > 1)
+      send_to_char(ch,
+          "You still have to achieve %d out of %d goals for the quest.\r\n",
+	  GET_QUEST_COUNTER(ch), QST_QUANTITY(rnum));
+    if (GET_QUEST_TIME(ch) > 0)
+      send_to_char(ch,
+          "You have %d turn%s remaining to complete the quest.\r\n",
+	  GET_QUEST_TIME(ch),
+	  GET_QUEST_TIME(ch) == 1 ? "" : "s");
+  }
+}
+
+void quest_show(struct char_data *ch, mob_rnum qm)
+{
+  qst_rnum rnum;
+  int counter = 0;
+
+  send_to_char(ch,
+  "The following quests are available:\r\n"
+  "Index Description                                          ( Vnum) Done?\r\n"
+  "----- ---------------------------------------------------- ------- -----\r\n");
+  for (rnum = 0; rnum < total_quests; rnum++)
+    if (qm == QST_MASTER(rnum))
+      send_to_char(ch, "@g%4d@n) @c%-52.52s@n @y(%5d)@n @y(%s)@n\r\n",
+        ++counter, QST_DESC(rnum), QST_NUM(rnum),
+        (is_complete(ch, QST_NUM(rnum)) ? "Yes" : "No "));
+  if (!counter)
+    send_to_char(ch, "There are no quests available here at the moment.\r\n");
+}
+
+void quest_stat(struct char_data *ch, char argument[MAX_STRING_LENGTH])
+{
+  qst_rnum rnum;
+  char buf[MAX_STRING_LENGTH];
+  char targetname[MAX_STRING_LENGTH];
+
+  if (GET_LEVEL(ch) < LVL_IMMORT)
+    send_to_char(ch, "Huh!?!\r\n");
+  else if (!*argument)
+    send_to_char(ch, "%s\r\n", quest_imm_usage);
+  else if ((rnum = real_quest(atoi(argument))) == NOTHING )
+    send_to_char(ch, "That quest does not exist.\r\n");
+  else {
+    sprintbit(QST_FLAGS(rnum), aq_flags, buf, sizeof(buf));
+    switch (QST_TYPE(rnum)) {
+      case AQ_OBJ_FIND:
+      case AQ_OBJ_RETURN:
+        snprintf(targetname, sizeof(targetname), "%s",
+                 real_object(QST_TARGET(rnum)) == NOTHING ?
+                 "An unknown object" :
+		 obj_proto[real_object(QST_TARGET(rnum))].short_description);
+	break;
+      case AQ_ROOM_FIND:
+      case AQ_ROOM_CLEAR:
+        snprintf(targetname, sizeof(targetname), "%s",
+	         real_room(QST_TARGET(rnum)) == NOWHERE ?
+                 "An unknown room" :
+		 world[real_room(QST_TARGET(rnum))].name);
+        break;
+      case AQ_MOB_FIND:
+      case AQ_MOB_KILL:
+      case AQ_MOB_SAVE:
+	snprintf(targetname, sizeof(targetname), "%s",
+                 real_mobile(QST_TARGET(rnum)) == NOBODY ?
+		 "An unknown mobile" :
+		 GET_NAME(&mob_proto[real_mobile(QST_TARGET(rnum))]));
+	break;
+      default:
+	snprintf(targetname, sizeof(targetname), "Unknown");
+	break;
+    }
+    send_to_char(ch,
+        "VNum  : [@y%5d@n], RNum: [@y%5d@n] -- Questmaster: [@y%5d@n] @y%s@n\r\n"
+        "Name  : @y%s@n\r\n"
+	"Desc  : @y%s@n\r\n"
+	"Accept Message:\r\n@c%s@n"
+	"Completion Message:\r\n@c%s@n"
+	"Quit Message:\r\n@c%s@n"
+	"Type  : @y%s@n\r\n"
+        "Target: @y%d@n @y%s@n, Quantity: @y%d@n\r\n"
+	"Value : @y%d@n, Penalty: @y%d@n, Min Level: @y%2d@n, Max Level: @y%2d@n\r\n"
+	"Flags : @c%s@n\r\n",
+    	QST_NUM(rnum), rnum,
+	QST_MASTER(rnum) == NOBODY ? -1 : mob_index[QST_MASTER(rnum)].vnum,
+	QST_MASTER(rnum) == NOBODY ? "" : GET_NAME(&mob_proto[QST_MASTER(rnum)]),
+        QST_NAME(rnum), QST_DESC(rnum),
+        QST_INFO(rnum), QST_DONE(rnum),
+	(QST_QUIT(rnum) &&
+	 (str_cmp(QST_QUIT(rnum), "undefined") != 0)
+       	 ? QST_QUIT(rnum) : "Nothing\r\n"),
+    	quest_types[QST_TYPE(rnum)],
+	QST_TARGET(rnum) == NOBODY ? -1 : QST_TARGET(rnum),
+	targetname,
+	QST_QUANTITY(rnum),
+    	QST_POINTS(rnum), QST_PENALTY(rnum), QST_MINLEVEL(rnum),
+	QST_MAXLEVEL(rnum), buf);
+    if (QST_PREREQ(rnum) != NOTHING)
+      send_to_char(ch, "Preq  : [@y%5d@n] @y%s@n\r\n",
+        QST_PREREQ(rnum) == NOTHING ? -1 : QST_PREREQ(rnum),
+        QST_PREREQ(rnum) == NOTHING ? "" :
+	  real_object(QST_PREREQ(rnum)) == NOTHING ? "an unknown object" :
+	      obj_proto[real_object(QST_PREREQ(rnum))].short_description);
+    if (QST_TYPE(rnum) == AQ_OBJ_RETURN)
+      send_to_char(ch, "Mob   : [@y%5d@n] @y%s@n\r\n",
+        QST_RETURNMOB(rnum),
+	real_mobile(QST_RETURNMOB(rnum)) == NOBODY ? "an unknown mob" :
+           mob_proto[real_mobile(QST_RETURNMOB(rnum))].player.short_descr);
+    if (QST_TIME(rnum) != -1)
+      send_to_char(ch, "Limit : There is a time limit of %d turn%s to complete.\r\n",
+	  QST_TIME(rnum),
+	  QST_TIME(rnum) == 1 ? "" : "s");
+    else
+      send_to_char(ch, "Limit : There is no time limit on this quest.\r\n");
+    send_to_char(ch, "Prior :");
+    if (QST_PREV(rnum) == NOTHING)
+      send_to_char(ch, " @yNone.@n\r\n");
+    else
+      send_to_char(ch, " [@y%5d@n] @c%s@n\r\n",
+        QST_PREV(rnum), QST_DESC(real_quest(QST_PREV(rnum))));
+    send_to_char(ch, "Next  :");
+    if (QST_NEXT(rnum) == NOTHING)
+      send_to_char(ch, " @yNone.@n\r\n");
+    else
+      send_to_char(ch, " [@y%5d@n] @c%s@n\r\n",
+        QST_NEXT(rnum), QST_DESC(real_quest(QST_NEXT(rnum))));
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+/* Quest Command Processing Function and Questmaster Special                */
+/*--------------------------------------------------------------------------*/
+
+ACMD(do_quest)
+{
+  char arg1[MAX_INPUT_LENGTH], arg2[MAX_INPUT_LENGTH];
+  int  tp;
+
+  two_arguments(argument, arg1, arg2);
+  if (!*arg1)
+    send_to_char(ch, "%s\r\n", GET_LEVEL(ch) < LVL_IMMORT ?
+                     quest_mort_usage : quest_imm_usage);
+  else if (((tp = search_block(arg1, quest_cmd, FALSE)) == -1))
+    send_to_char(ch, "%s\r\n", GET_LEVEL(ch) < LVL_IMMORT ?
+                     quest_mort_usage : quest_imm_usage);
+  else {
+    switch (tp) {
+      case SCMD_QUEST_LIST:
+      case SCMD_QUEST_JOIN:
+        /* list, join should hve been handled by questmaster spec proc */
+        send_to_char(ch, "Sorry, but you cannot do that here!\r\n");
+        break;
+      case SCMD_QUEST_HISTORY:
+        quest_hist(ch);
+        break;
+      case SCMD_QUEST_LEAVE:
+        quest_quit(ch);
+        break;
+      case SCMD_QUEST_PROGRESS:
+	quest_progress(ch);
+	break;
+      case SCMD_QUEST_STATUS:
+        if (GET_LEVEL(ch) < LVL_IMMORT)
+          send_to_char(ch, "%s\r\n", quest_mort_usage);
+        else
+          quest_stat(ch, arg2);
+        break;
+      default: /* Whe should never get here, but... */
+        send_to_char(ch, "%s\r\n", GET_LEVEL(ch) < LVL_IMMORT ?
+                     quest_mort_usage : quest_imm_usage);
+	break;
+    } /* switch on subcmd number */
+  }
+}
+
+SPECIAL(questmaster)
+{
+  qst_rnum rnum;
+  char arg1[MAX_INPUT_LENGTH], arg2[MAX_INPUT_LENGTH];
+  int  tp;
+  struct char_data *qm = (struct char_data *)me;
+
+  /* check that qm mob has quests assigned */
+  for (rnum = 0; (rnum < total_quests &&
+                  QST_MASTER(rnum) != GET_MOB_RNUM(qm)) ; rnum ++);
+  if (rnum >= total_quests)
+    return FALSE; /* No quests for this mob */
+  else if (QST_FUNC(rnum) && (QST_FUNC(rnum) (ch, me, cmd, argument)))
+    return TRUE;  /* The secondary spec proc handled this command */
+  else if (CMD_IS("quest")) {
+    two_arguments(argument, arg1, arg2);
+    if (!*arg1)
+      return FALSE;
+    else if (((tp = search_block(arg1, quest_cmd, FALSE)) == -1))
+      return FALSE;
+    else {
+      switch (tp) {
+      case SCMD_QUEST_LIST:
+        if (!*arg2)
+          quest_show(ch, GET_MOB_RNUM(qm));
+        else
+	  quest_list(ch, qm, arg2);
+        break;
+      case SCMD_QUEST_JOIN:
+        quest_join(ch, qm, arg2);
+        break;
+      default:
+	return FALSE; /* fall through to the do_quest command processor */
+      } /* switch on subcmd number */
+      return TRUE;
+    }
+  } else {
+    return FALSE; /* not a questmaster command */
+  }
+}
diff -BbuprN tbamud-3.55/src/quest.h tbamud-3.55+quests/src/quest.h
--- tbamud-3.55/src/quest.h	1970-01-01 00:00:00.000000000 +0000
+++ tbamud-3.55+quests/src/quest.h	2008-01-31 11:56:26.881922000 +0000
@@ -0,0 +1,142 @@
+/* ***********************************************************************
+*    File:   quest.h                                  Part of CircleMUD  *
+* Version:   2.1 (December 2005) Written for CircleMud CWG / Suntzu      *
+* Purpose:   To provide special quest-related code.                      *
+* Copyright: Kenneth Ray                                                 *
+* Original Version Details:                                              *
+* Morgaelin - quest.h						         *
+* Copyright (C) 1997 MS                                                  *
+*********************************************************************** */
+
+/* Aquest related defines ********************************************* */
+#define AQ_UNDEFINED       -1   /* (R) Quest unavailable                */
+#define AQ_OBJ_FIND         0   /* Player must retreive object          */
+#define AQ_ROOM_FIND        1   /* Player must reach room               */
+#define AQ_MOB_FIND         2   /* Player must find mob                 */
+#define AQ_MOB_KILL         3   /* Player must kill mob                 */
+#define AQ_MOB_SAVE         4   /* Player must save mob                 */
+#define AQ_OBJ_RETURN       5   /* Player gives object to mob in val5   */
+#define AQ_ROOM_CLEAR       6   /* Player must clear room of all mobs   */
+#define NUM_AQ_TYPES        7   /* Used in qedit functions              */
+
+#define MAX_QUEST_NAME     40   /* Length of quest name                 */
+#define MAX_QUEST_DESC     75   /* Length of quest description          */
+#define MAX_QUEST_MSG    2048   /* Length of quest message strings      */
+
+#define SCMD_QUEST_LIST     0   /* List quests available at questmaster */
+#define SCMD_QUEST_HISTORY  1   /* Show history of completed quests     */
+#define SCMD_QUEST_JOIN     2   /* Join a quest at a questmaster        */
+#define SCMD_QUEST_LEAVE    3   /* Leave a quest                        */
+#define SCMD_QUEST_PROGRESS 4   /* Show progress of current quest       */
+#define SCMD_QUEST_STATUS   5   /* Show complete details of a quest     */
+/* AQ Flags (much room for expansion) ********************************* */
+#define AQ_REPEATABLE (1 << 0)  /* Quest can be repeated                */
+#define NUM_AQ_FLAGS        1
+/* Main quest struct ************************************************** */
+struct aq_data {
+  qst_vnum vnum;                /* Virtual nr of the quest              */
+  char     *name;               /* For qlist and the sort               */
+  char     *desc;               /* Description of the quest             */
+  char     *info;               /* Message displayed when accepted      */
+  char     *done;               /* Message displayed when completed     */
+  char     *quit;               /* Message displayed when quit quest    */
+  long     flags;               /* Flags (repeatable, etc               */
+  int      type;                /* Quest type                           */
+  mob_rnum qm;                  /* questmaster offering quest           */
+  int      target;              /* Target value                         */
+  obj_vnum prereq;              /* Object required to undertake quest   */
+  int      value[7];            /* Quest values                         */
+  int      gold_reward;         /* Number of gold coins given as reward */
+  int      exp_reward;          /* Experience points given as a reward  */
+  obj_vnum obj_reward;          /* vnum of object given as a reward     */
+  qst_vnum prev_quest;          /* Link to prev quest, NOTHING is open  */
+  qst_vnum next_quest;          /* Link to next quest, NOTHING is end   */
+  SPECIAL  (*func);             /* secondary spec_proc for the QM       */
+};
+#define QST_NUM(i)             (aquest_table[i].vnum)
+#define QST_NAME(i)            (aquest_table[i].name)
+#define QST_DESC(i)            (aquest_table[i].desc)
+#define QST_INFO(i)            (aquest_table[i].info)
+#define QST_DONE(i)            (aquest_table[i].done)
+#define QST_QUIT(i)            (aquest_table[i].quit)
+#define QST_TYPE(i)            (aquest_table[i].type)
+#define QST_FLAGS(i)           (aquest_table[i].flags)
+#define QST_MASTER(i)          (aquest_table[i].qm)
+#define QST_TARGET(i)          (aquest_table[i].target)
+#define QST_PREREQ(i)          (aquest_table[i].prereq)
+#define QST_POINTS(i)          (aquest_table[i].value[0])
+#define QST_PENALTY(i)         (aquest_table[i].value[1])
+#define QST_MINLEVEL(i)        (aquest_table[i].value[2])
+#define QST_MAXLEVEL(i)        (aquest_table[i].value[3])
+#define QST_TIME(i)            (aquest_table[i].value[4])
+#define QST_RETURNMOB(i)       (aquest_table[i].value[5])
+#define QST_QUANTITY(i)        (aquest_table[i].value[6])
+#define QST_GOLD(i)            (aquest_table[i].gold_reward)
+#define QST_EXP(i)             (aquest_table[i].exp_reward)
+#define QST_OBJ(i)             (aquest_table[i].obj_reward)
+
+#define QST_FUNC(i)            (aquest_table[i].func)
+#define QST_PREV(i)            (aquest_table[i].prev_quest)
+#define QST_NEXT(i)            (aquest_table[i].next_quest)
+/* Quest Functions **************************************************** */
+/* Implemented in quest.c */
+void destroy_quests(void);
+void assign_the_quests(void);
+void parse_quest(FILE *quest_f, int nr);
+int  count_quests(qst_vnum low, qst_vnum high);
+void list_quests(struct char_data *ch, zone_rnum zone, qst_vnum vmin, qst_vnum vmax);
+void set_quest(struct char_data *ch, qst_rnum rnum);
+void clear_quest(struct char_data *ch);
+void generic_complete_quest(struct char_data *ch);
+void autoquest_trigger_check(struct char_data *ch, struct char_data *vict, struct obj_data *object, int type);
+qst_rnum real_quest(qst_vnum vnum);
+int is_complete(struct char_data *ch, qst_vnum vnum);
+qst_vnum find_quest_by_qmnum(struct char_data *ch, mob_rnum qm, int num);
+void add_completed_quest(struct char_data *ch, qst_vnum vnum);
+void remove_completed_quest(struct char_data *ch, qst_vnum vnum);
+void quest_timeout(struct char_data *ch);
+void check_timed_quests(void);
+SPECIAL(questmaster);
+/* Implemented in qedit.c  */
+void qedit_parse(struct descriptor_data *d, char *arg);
+void qedit_string_cleanup(struct descriptor_data *d, int terminator);
+/* Implemented in genqst.c */
+int copy_quest_strings(struct aq_data *from, struct aq_data *to);
+int copy_quest(struct aq_data *from, struct aq_data *to, int free_old_strings);
+void free_quest_strings(struct aq_data *quest);
+void free_quest(struct aq_data *quest);
+int add_quest(struct aq_data *nqst);
+int delete_quest(qst_rnum rnum);
+int save_quests(zone_rnum zone_num);
+/* AQ Global Variables ************************************************ */
+extern struct aq_data *aquest_table; /* all quest definitions (db.c)    */
+extern qst_rnum total_quests;        /* number of quests      (db.c)    */
+extern const char *aq_flags[];       /* names for quest flags (quest.c) */
+extern const char *quest_types[];    /* named for quest types (quest.c) */
+/* Qedit Connectedness ************************************************ */
+#define QEDIT_MAIN_MENU                 0
+#define QEDIT_CONFIRM_SAVESTRING        1
+#define QEDIT_NAME                      2
+#define QEDIT_DESC                      3
+#define QEDIT_INFO                      4
+#define QEDIT_COMPLETE                  5
+#define QEDIT_ABANDON                   6
+#define QEDIT_QUESTMASTER               7
+#define QEDIT_TYPES                     8
+#define QEDIT_FLAGS                     9
+#define QEDIT_TARGET                   10
+#define QEDIT_QUANTITY                 11
+#define QEDIT_POINTSCOMP               12
+#define QEDIT_POINTSQUIT               13
+#define QEDIT_LEVELMIN                 14
+#define QEDIT_LEVELMAX                 15
+#define QEDIT_PREREQ                   16
+#define QEDIT_TIMELIMIT                17
+#define QEDIT_RETURNMOB                18
+#define QEDIT_NEXTQUEST                19
+#define QEDIT_PREVQUEST                20
+#define QEDIT_CONFIRM_DELETE           21
+#define QEDIT_GOLD                     22
+#define QEDIT_EXP                      23
+#define QEDIT_OBJ                      24
+/* ******************************************************************** */
diff -BbuprN tbamud-3.55/src/shop.c tbamud-3.55+quests/src/shop.c
--- tbamud-3.55/src/shop.c	2008-01-16 23:21:14.000000000 +0000
+++ tbamud-3.55+quests/src/shop.c	2008-01-31 12:27:30.772547000 +0000
@@ -503,6 +503,16 @@ void shopping_buy(char *arg, struct char
   if (!(obj = get_purchase_obj(ch, arg, keeper, shop_nr, TRUE)))
     return;
 
+  if (OBJ_FLAGGED(obj, ITEM_QUEST)) {
+    if (GET_OBJ_COST(obj) > GET_QUESTPOINTS(ch) && !IS_GOD(ch)) {
+      char actbuf[MAX_INPUT_LENGTH];
+      snprintf(actbuf, sizeof(actbuf),
+	       "%s You haven't earned enough quest points for such an item.",
+	       GET_NAME(ch));
+      do_tell(keeper, actbuf, cmd_tell, 0);
+      return;
+    }
+  } else { /*has the player got enough gold? */
   if (buy_price(obj, shop_nr, keeper, ch) > GET_GOLD(ch) && !IS_GOD(ch)) {
     char actbuf[MAX_INPUT_LENGTH];
 
@@ -520,6 +530,7 @@ void shopping_buy(char *arg, struct char
       return;
     }
   }
+  }
   if (IS_CARRYING_N(ch) + 1 > CAN_CARRY_N(ch)) {
     send_to_char(ch, "%s: You can't carry any more items.\r\n", fname(obj->name));
     return;
@@ -528,6 +539,32 @@ void shopping_buy(char *arg, struct char
     send_to_char(ch, "%s: You can't carry that much weight.\r\n", fname(obj->name));
     return;
   }
+  if (OBJ_FLAGGED(obj, ITEM_QUEST)) {
+    while (obj &&
+           (GET_QUESTPOINTS(ch) >= GET_OBJ_COST(obj) || IS_GOD(ch))
+	   && IS_CARRYING_N(ch) < CAN_CARRY_N(ch)
+	   && bought < buynum
+	   && IS_CARRYING_W(ch) + GET_OBJ_WEIGHT(obj) <= CAN_CARRY_W(ch)) {
+      bought++;
+      /* Test if producing shop ! */
+      if (shop_producing(obj, shop_nr)) {
+        obj = read_object(GET_OBJ_RNUM(obj), REAL);
+      } else {
+        obj_from_char(obj);
+        SHOP_SORT(shop_nr)--;
+      }
+      obj_to_char(obj, ch);
+
+      goldamt += GET_OBJ_COST(obj);
+      if (!IS_GOD(ch))
+        GET_QUESTPOINTS(ch) -= GET_OBJ_COST(obj);
+
+      last_obj = obj;
+      obj = get_purchase_obj(ch, arg, keeper, shop_nr, FALSE);
+      if (!same_obj(obj, last_obj))
+        break;
+    }
+  } else {
   while (obj && (GET_GOLD(ch) >= buy_price(obj, shop_nr, keeper, ch) || IS_GOD(ch))
 	 && IS_CARRYING_N(ch) < CAN_CARRY_N(ch) && bought < buynum
 	 && IS_CARRYING_W(ch) + GET_OBJ_WEIGHT(obj) <= CAN_CARRY_W(ch)) {
@@ -553,14 +590,19 @@ void shopping_buy(char *arg, struct char
     if (!same_obj(obj, last_obj))
       break;
   }
-
+  }
   if (bought < buynum) {
     char buf[MAX_INPUT_LENGTH];
 
     if (!obj || !same_obj(last_obj, obj))
       snprintf(buf, sizeof(buf), "%s I only have %d to sell you.", GET_NAME(ch), bought);
-    else if (GET_GOLD(ch) < buy_price(obj, shop_nr, keeper, ch))
+    else if (!OBJ_FLAGGED(obj, ITEM_QUEST) &&
+             GET_GOLD(ch) < buy_price(obj, shop_nr, keeper, ch))
       snprintf(buf, sizeof(buf), "%s You can only afford %d.", GET_NAME(ch), bought);
+    else if (OBJ_FLAGGED(obj, ITEM_QUEST) &&
+             GET_QUESTPOINTS(ch) < GET_OBJ_COST(obj))
+      snprintf(buf, sizeof(buf), "%s You only had sufficient quest points for %d.",
+	       GET_NAME(ch), bought);
     else if (IS_CARRYING_N(ch) >= CAN_CARRY_N(ch))
       snprintf(buf, sizeof(buf), "%s You can only hold %d.", GET_NAME(ch), bought);
     else if (IS_CARRYING_W(ch) + GET_OBJ_WEIGHT(obj) > CAN_CARRY_W(ch))
@@ -569,15 +611,25 @@ void shopping_buy(char *arg, struct char
       snprintf(buf, sizeof(buf), "%s Something screwy only gave you %d.", GET_NAME(ch), bought);
     do_tell(keeper, buf, cmd_tell, 0);
   }
-  if (!IS_GOD(ch))
+  if (!IS_GOD(ch) && !OBJ_FLAGGED(obj, ITEM_QUEST)) {
     GET_GOLD(keeper) += goldamt;
+    if (SHOP_USES_BANK(shop_nr))
+      if (GET_GOLD(keeper) > MAX_OUTSIDE_BANK) {
+        SHOP_BANK(shop_nr) += (GET_GOLD(keeper) - MAX_OUTSIDE_BANK);
+        GET_GOLD(keeper) = MAX_OUTSIDE_BANK;
+      }
+  }
 
   strlcpy(tempstr, times_message(ch->carrying, 0, bought), sizeof(tempstr));
 
   snprintf(tempbuf, sizeof(tempbuf), "$n buys %s.", tempstr);
   act(tempbuf, FALSE, ch, obj, 0, TO_ROOM);
 
+  if (OBJ_FLAGGED(obj, ITEM_QUEST))
+    snprintf(tempbuf, sizeof(tempbuf), "%s That has cost you %d quest points.", GET_NAME(ch), goldamt);
+  else
   snprintf(tempbuf, sizeof(tempbuf), shop_index[shop_nr].message_buy, GET_NAME(ch), goldamt);
+
   do_tell(keeper, tempbuf, cmd_tell, 0);
 
   send_to_char(ch, "You now have %s.\r\n", tempstr);
@@ -581,12 +633,6 @@ void shopping_buy(char *arg, struct char
   do_tell(keeper, tempbuf, cmd_tell, 0);
 
   send_to_char(ch, "You now have %s.\r\n", tempstr);
-
-  if (SHOP_USES_BANK(shop_nr))
-    if (GET_GOLD(keeper) > MAX_OUTSIDE_BANK) {
-      SHOP_BANK(shop_nr) += (GET_GOLD(keeper) - MAX_OUTSIDE_BANK);
-      GET_GOLD(keeper) = MAX_OUTSIDE_BANK;
-    }
 }
 
 struct obj_data *get_selling_obj(struct char_data *ch, char *name, struct char_data *keeper, int shop_nr, int msg)
@@ -817,7 +863,7 @@ char *list_object(struct obj_data *obj, 
   }
   CAP(itemname);
 
-  snprintf(result, sizeof(result), " %2d)  %9s   %-*s %6d\r\n", aindex, quantity, count_color_chars(itemname)+48, itemname, buy_price(obj, shop_nr, keeper, ch));
+  snprintf(result, sizeof(result), " %2d)  %9s   %-*s %6d%s\r\n", aindex, quantity, count_color_chars(itemname)+48, itemname, buy_price(obj, shop_nr, keeper, ch), OBJ_FLAGGED(obj, ITEM_QUEST) ? " qp" : "");
 
   return (result);
 }
@@ -826,9 +872,10 @@ void shopping_list(char *arg, struct cha
 {
   char buf[MAX_STRING_LENGTH], name[MAX_INPUT_LENGTH];
   struct obj_data *obj, *last_obj = NULL;
-  int cnt = 0, lindex = 0, found = FALSE;
+  int cnt = 0, lindex = 0, found = FALSE, has_quest = FALSE;
   size_t len;
   /* cnt is the number of that particular object available */
+  /* has_quest indicates if the shopkeeper sells quest items */
 
   if (!is_ok(keeper, ch, shop_nr))
     return;
@@ -839,7 +886,7 @@ void shopping_list(char *arg, struct cha
   one_argument(arg, name);
 
   len = strlcpy(buf,   " ##   Available   Item                                               Cost\r\n"
-		"-------------------------------------------------------------------------\r\n", sizeof(buf));
+		"----------------------------------------------------------------------------\r\n", sizeof(buf));
   if (keeper->carrying)
     for (obj = keeper->carrying; obj; obj = obj->next_content)
       if (CAN_SEE_OBJ(ch, obj) && GET_OBJ_COST(obj) > 0) {
@@ -856,6 +903,8 @@ void shopping_list(char *arg, struct cha
             if (len + 1 >= sizeof(buf))
               break;
             found = TRUE;
+            if (OBJ_FLAGGED(last_obj, ITEM_QUEST))
+              has_quest = TRUE;
           }
 	  cnt = 1;
 	  last_obj = obj;
@@ -871,6 +920,8 @@ void shopping_list(char *arg, struct cha
       if (len < sizeof(buf))
         strncat(buf, list_object(last_obj, cnt, lindex, shop_nr, keeper, ch), sizeof(buf) - len - 1);	/* strncat: OK */
     page_string(ch->desc, buf, TRUE);
+    if (has_quest)
+      send_to_char(ch, "Items flagged \"qp\" require quest points to purchase.\r\n");
   }
 }
 
@@ -1279,8 +1330,8 @@ void list_all_shops(struct char_data *ch
 void list_detailed_shop(struct char_data *ch, int shop_nr)
 {
   struct char_data *k;
-  int sindex, column;
-  char *ptrsave;
+  int sindex, column, flag = 1, found = 0;
+//char *ptrsave;
 
   send_to_char(ch, "Vnum:       [%5d], Rnum: [%5d]\r\n", SHOP_NUM(shop_nr), shop_nr + 1);
 
@@ -1327,7 +1378,33 @@ void list_detailed_shop(struct char_data
   } else
     send_to_char(ch, "<NONE>\r\n");
 
-  send_to_char(ch, "Customers:  %s\r\n", (ptrsave = customer_string(shop_nr, TRUE)) ? ptrsave : "None");
+//  send_to_char(ch, "Customers:  %s\r\n", (ptrsave = customer_string(shop_nr, TRUE)) ? ptrsave : "None");
+  send_to_char(ch, "Customers:  ");
+  column = 12;  /* ^^^ strlen ^^^ */
+  for (sindex = 0; *trade_letters[sindex] != '\n'; sindex++) {
+    char buf1[128];
+    int linelen;
+
+    if (!IS_SET(flag, SHOP_TRADE_WITH(shop_nr))){
+      if (sindex) {
+        send_to_char(ch, ", ");
+        column += 2;
+      }
+      linelen = snprintf(buf1, sizeof(buf1), "%s", trade_letters[sindex]);
+      /* Implementing word-wrapping: assumes screen-size == 80 */
+      if (linelen + column >= 78 && column >= 20) {
+        send_to_char(ch, "\r\n            ");
+        column = 12;
+      }
+
+      if (!send_to_char(ch, "%s", buf1))
+        return;
+      column += linelen;
+      found = TRUE;
+    }
+    flag <<= 1; /* next flag */
+  }
+  send_to_char(ch, "%s\r\n", found ? "" : "Nobody!");
 
   send_to_char(ch, "Produces:   ");
   column = 12;	/* ^^^ strlen ^^^ */
diff -BbuprN tbamud-3.55/src/structs.h tbamud-3.55+quests/src/structs.h
--- tbamud-3.55/src/structs.h	2008-01-16 23:21:16.000000000 +0000
+++ tbamud-3.55+quests/src/structs.h	2008-01-31 11:13:03.741297000 +0000
@@ -265,6 +265,7 @@
 #define CON_AEDIT        25     /* OLC mode - social (action) edit      */
 #define CON_TRIGEDIT     26	/* OLC mode - trigger edit              */
 #define CON_HEDIT        27
+#define CON_QEDIT        28     /* OLC mode - quest edit                */
 
 /* Character equipment positions: used as index for char_data.equipment[] */
 /* NOTE: Don't confuse these constants with the ITEM_ bitvectors
@@ -351,6 +352,7 @@
 #define ITEM_ANTI_THIEF	      14   /* Not usable by thieves */
 #define ITEM_ANTI_WARRIOR     15   /* Not usable by warriors */
 #define ITEM_NOSELL           16   /* Shopkeepers won't touch it */
+#define ITEM_QUEST            17 /* Item is a quest item         */
 
 /* Modifier constants used with obj affects ('A' fields) */
 #define APPLY_NONE              0	/* No effect			*/
@@ -500,6 +502,7 @@
 #define MAX_LAST_ENTRIES        6000  /* arbitrary */
 #define MAX_HELP_KEYWORDS       256
 #define MAX_HELP_ENTRY          MAX_STRING_LENGTH
+#define MAX_COMPLETED_QUESTS    1024
 
 /* define the largest set of commands for a trigger */
 #define MAX_CMD_LENGTH 16384         /* 16k should be plenty and then some */
@@ -524,6 +527,7 @@ typedef IDXTYPE mob_vnum;
 typedef IDXTYPE zone_vnum;
 typedef IDXTYPE shop_vnum;
 typedef IDXTYPE trig_vnum;
+typedef IDXTYPE qst_vnum;
 
 /* Various real (array-reference) number types. */
 typedef IDXTYPE room_rnum;
@@ -532,6 +536,7 @@ typedef IDXTYPE mob_rnum;
 typedef IDXTYPE zone_rnum;
 typedef IDXTYPE shop_rnum;
 typedef IDXTYPE trig_rnum;
+typedef IDXTYPE qst_rnum;
 
 /* Bitvector type for 32 bit unsigned long bitvectors. 'unsigned long long' 
  * will give you at least 64 bits if you have GCC. You'll have to search 
@@ -775,6 +780,11 @@ struct player_special_data_saved {
    int spells_to_learn;         /* How many spells you can learn */
    int olc_zone;                /* A players olc access */
    int questpoints;             /* A players questpoints earned */
+   qst_vnum *completed_quests;           /* Quests completed              */
+   int    num_completed_quests;          /* Number completed              */
+   int    current_quest;                 /* vnum of current quest         */
+   int    quest_time;                    /* time left on current quest    */
+   int    quest_counter;                 /* Count of targets left to get  */
 };
 
 /* Specials needed only by PCs, not NPCs.  Space for this structure is
diff -BbuprN tbamud-3.55/src/utils.h tbamud-3.55+quests/src/utils.h
--- tbamud-3.55/src/utils.h	2008-01-16 23:21:14.000000000 +0000
+++ tbamud-3.55+quests/src/utils.h	2008-01-31 11:16:50.631922000 +0000
@@ -316,7 +316,13 @@ void char_from_furniture(struct char_dat
 #define GET_HOST(ch)		CHECK_PLAYER_SPECIAL((ch), ((ch)->player_specials->host))
 #define GET_HISTORY(ch, i)      CHECK_PLAYER_SPECIAL((ch), ((ch)->player_specials->saved.comm_hist[i]))
 #define GET_PAGE_LENGTH(ch)     CHECK_PLAYER_SPECIAL((ch), ((ch)->player_specials->saved.page_length))
+/* Autoquests data */
 #define GET_QUESTPOINTS(ch)     CHECK_PLAYER_SPECIAL((ch), ((ch)->player_specials->saved.questpoints))
+#define GET_QUEST(ch)           CHECK_PLAYER_SPECIAL((ch), ((ch)->player_specials->saved.current_quest))
+#define GET_QUEST_COUNTER(ch)   CHECK_PLAYER_SPECIAL((ch), ((ch)->player_specials->saved.quest_counter))
+#define GET_QUEST_TIME(ch)      CHECK_PLAYER_SPECIAL((ch), ((ch)->player_specials->saved.quest_time))
+#define GET_NUM_QUESTS(ch)      CHECK_PLAYER_SPECIAL((ch), ((ch)->player_specials->saved.num_completed_quests))
+#define GET_QUEST_TYPE(ch)      (real_quest(GET_QUEST((ch))) != NOTHING ? aquest_table[real_quest(GET_QUEST((ch)))].type : AQ_UNDEFINED )
 
 #define GET_SKILL(ch, i)	CHECK_PLAYER_SPECIAL((ch), ((ch)->player_specials->saved.skills[i]))
 #define SET_SKILL(ch, i, pct)	do { CHECK_PLAYER_SPECIAL((ch), (ch)->player_specials->saved.skills[i]) = pct; } while(0)
diff -BbuprN tbamud-3.55/src/zedit.c tbamud-3.55+quests/src/zedit.c
--- tbamud-3.55/src/zedit.c	2008-01-16 23:21:16.000000000 +0000
+++ tbamud-3.55+quests/src/zedit.c	2008-01-31 11:17:40.069422000 +0000
@@ -263,6 +263,7 @@ void zedit_new_zone(struct char_data *ch
       case CON_SEDIT:
       case CON_OEDIT:
       case CON_TRIGEDIT:
+      case CON_QEDIT:
         OLC_ZNUM(dsc) += (OLC_ZNUM(dsc) >= result);
         break;
       default:
