diff -uprN -x *.o circle30bpl12/src/Makefile multi/src/Makefile
--- circle30bpl12/src/Makefile	Thu Dec  4 02:55:58 1997
+++ multi/src/Makefile	Wed Dec  3 05:17:15 1997
@@ -19,7 +19,7 @@ BINDIR = ../bin
 
 CFLAGS = -g -O2 $(MYFLAGS) $(PROFILE)
 
-OBJFILES = comm.o act.comm.o act.informative.o act.movement.o act.item.o \
+OBJFILES = multi.o comm.o act.comm.o act.informative.o act.movement.o act.item.o \
 	act.offensive.o act.other.o act.social.o act.wizard.o ban.o boards.o \
 	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 \
@@ -30,7 +30,7 @@ CXREF_FILES = act.comm.c act.informative
 	act.offensive.c act.other.c act.social.c act.wizard.c ban.c boards.c \
 	castle.c class.c comm.c config.c constants.c db.c fight.c graph.c \
 	handler.c house.c interpreter.c limits.c magic.c mail.c mobact.c \
-	modify.c objsave.c olc.c random.c shop.c spec_assign.c spec_procs.c \
+	modify.c multi.c objsave.c olc.c random.c shop.c spec_assign.c spec_procs.c \
 	spell_parser.c spells.c utils.c weather.c
 
 default: all
@@ -192,3 +192,6 @@ 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
+multi.o: multi.c conf.h sysdep.h structs.h utils.h db.h interpreter.h \
+ comm.h
+	$(CC) -c $(CFLAGS) multi.c
diff -uprN -x *.o circle30bpl12/src/act.informative.c multi/src/act.informative.c
--- circle30bpl12/src/act.informative.c	Tue Oct 28 15:16:22 1997
+++ multi/src/act.informative.c	Wed Dec  3 06:16:40 1997
@@ -671,8 +671,8 @@ ACMD(do_score)
     sprintf(buf, "%sYou have been playing for %d days and %d hours.\r\n",
 	  buf, playing_time.day, playing_time.hours);
 
-    sprintf(buf, "%sThis ranks you as %s %s (level %d).\r\n", buf,
-	  GET_NAME(ch), GET_TITLE(ch), GET_LEVEL(ch));
+    sprintf(buf, "%sThis ranks you as %s %s (level %d, Total Level %d).\r\n", buf,
+	  GET_NAME(ch), GET_TITLE(ch), GET_LEVEL(ch), GET_TOT_LEVEL(ch));
   }
 
   switch (GET_POS(ch)) {
@@ -1002,9 +1002,9 @@ ACMD(do_who)
       send_to_char(buf, ch);
     } else {
       num_can_see++;
-      sprintf(buf, "%s[%2d %s] %s %s",
+      sprintf(buf, "%s[%2d - %-4d %s] %s %s",
 	      (GET_LEVEL(tch) >= LVL_IMMORT ? CCYEL(ch, C_SPR) : ""),
-	      GET_LEVEL(tch), CLASS_ABBR(tch), GET_NAME(tch),
+	      GET_LEVEL(tch), GET_TOT_LEVEL(tch), CLASS_ABBR(tch), GET_NAME(tch),
 	      GET_TITLE(tch));
 
       if (GET_INVIS_LEV(tch))
diff -uprN -x *.o circle30bpl12/src/act.wizard.c multi/src/act.wizard.c
--- circle30bpl12/src/act.wizard.c	Tue Oct 28 14:16:22 1997
+++ multi/src/act.wizard.c	Wed Dec  3 06:22:46 1997
@@ -1234,6 +1234,7 @@ ACMD(do_advance)
   if (newlevel < GET_LEVEL(victim)) {
     do_start(victim);
     GET_LEVEL(victim) = newlevel;
+    GET_TOT_LEVEL(victim) -= (oldlevel - newlevel);
     send_to_char("You are momentarily enveloped by darkness!\r\n"
 		 "You feel somewhat diminished.\r\n", victim);
   } else {
diff -uprN -x *.o circle30bpl12/src/class.c multi/src/class.c
--- circle30bpl12/src/class.c	Tue Oct 28 15:16:22 1997
+++ multi/src/class.c	Wed Dec  3 05:55:18 1997
@@ -290,6 +290,7 @@ void do_start(struct char_data * ch)
   void advance_level(struct char_data * ch);
 
   GET_LEVEL(ch) = 1;
+  GET_TOT_LEVEL(ch) = 1;
   GET_EXP(ch) = 1;
 
   set_title(ch, NULL);
diff -uprN -x *.o circle30bpl12/src/db.c multi/src/db.c
--- circle30bpl12/src/db.c	Tue Oct 28 14:16:24 1997
+++ multi/src/db.c	Wed Dec  3 05:52:04 1997
@@ -2285,6 +2285,7 @@ void init_char(struct char_data * ch)
   if (top_of_p_table == 0) {
     GET_EXP(ch) = 7000000;
     GET_LEVEL(ch) = LVL_IMPL;
+    GET_TOT_LEVEL(ch) = LVL_IMPL * NUM_CLASSES;
 
     ch->points.max_hit = 500;
     ch->points.max_mana = 100;
diff -uprN -x *.o circle30bpl12/src/interpreter.c multi/src/interpreter.c
--- circle30bpl12/src/interpreter.c	Tue Oct 28 14:16:28 1997
+++ multi/src/interpreter.c	Wed Dec  3 06:04:14 1997
@@ -111,6 +111,7 @@ ACMD(do_levels);
 ACMD(do_load);
 ACMD(do_look);
 ACMD(do_move);
+ACMD(do_multi);
 ACMD(do_not_here);
 ACMD(do_offer);
 ACMD(do_olc);
@@ -349,6 +350,7 @@ const struct command_info cmd_info[] = {
   { "motd"     , POS_DEAD    , do_gen_ps   , 0, SCMD_MOTD },
   { "mail"     , POS_STANDING, do_not_here , 1, 0 },
   { "massage"  , POS_RESTING , do_action   , 0, 0 },
+  { "multi"    , POS_STANDING, do_multi    , 1, 0 },
   { "mute"     , POS_DEAD    , do_wizutil  , LVL_GOD, SCMD_SQUELCH },
   { "murder"   , POS_FIGHTING, do_hit      , 0, SCMD_MURDER },
 
@@ -1521,6 +1523,8 @@ void nanny(struct descriptor_data *d, ch
     if (GET_PFILEPOS(d->character) < 0)
       GET_PFILEPOS(d->character) = create_entry(GET_NAME(d->character));
     init_char(d->character);
+    SET_BIT(MULTI_FLAGS(d->character), (1 << (int)GET_CLASS(d->character)));
+
     save_char(d->character, NOWHERE);
     SEND_TO_Q(motd, d);
     SEND_TO_Q("\r\n\n*** PRESS RETURN: ", d);
diff -uprN -x *.o circle30bpl12/src/limits.c multi/src/limits.c
--- circle30bpl12/src/limits.c	Tue Oct 28 14:16:28 1997
+++ multi/src/limits.c	Wed Dec  3 06:13:15 1997
@@ -248,6 +248,7 @@ void gain_exp(struct char_data * ch, int
     while (GET_LEVEL(ch) < LVL_IMMORT &&
 	GET_EXP(ch) >= level_exp(GET_CLASS(ch), GET_LEVEL(ch) + 1)) {
       GET_LEVEL(ch) += 1;
+      GET_TOT_LEVEL(ch) += 1;
       num_levels++;
       advance_level(ch);
       is_altered = TRUE;
@@ -285,6 +286,7 @@ void gain_exp_regardless(struct char_dat
     while (GET_LEVEL(ch) < LVL_IMPL &&
 	GET_EXP(ch) >= level_exp(GET_CLASS(ch), GET_LEVEL(ch) + 1)) {
       GET_LEVEL(ch) += 1;
+      GET_TOT_LEVEL(ch) += 1;
       num_levels++;
       advance_level(ch);
       is_altered = TRUE;
diff -uprN -x *.o circle30bpl12/src/multi.c multi/src/multi.c
--- circle30bpl12/src/multi.c	Wed Dec 31 19:00:00 1969
+++ multi/src/multi.c	Wed Dec  3 05:55:40 1997
@@ -0,0 +1,161 @@
+/*********************************************************************\
+ * File  : multi.c                                Based on CircleMUD *
+ * Usage : Controls player multi levels                              *
+ * By    : The Finality Development Team                             *
+ *   								     *
+ * Used with permission from Finality.com                            *
+\*********************************************************************/
+
+#include "conf.h"
+#include "sysdep.h"
+#include "structs.h"
+#include "utils.h"
+#include "db.h"
+#include "interpreter.h"
+#include "comm.h"
+
+extern char *pc_class_types[];
+
+/* CUSTOMIZABLE OPTIONS	*/
+
+/* Multi system defines */
+#define MULTI_MAGIC_USER	(1 << 0) /* Has multied to magic user */
+#define MULTI_CLERIC		(1 << 1) /* Has multied to cleric     */
+#define MULTI_THIEF		(1 << 2) /* Has multied to thief      */
+#define MULTI_WARRIOR		(1 << 3) /* Has multied to warrior    */
+
+/* Add new defines above, adding in sequential order. 
+ * ie: Next would be (1 << 4) 
+ */
+
+/* Set to -1 if you don't want a char to be in a particular room, otherwise
+ * set to whatever room you wish.
+ */
+#define MULTI_ROOM		3031
+
+/* The level you wish to be the multi level */
+#define MULTI_LEVEL		(LVL_IMMORT - 1)
+
+/* Stats char should start at after multi */
+#define MULTI_HP		20
+#define MULTI_MANA		100
+#define MULTI_MOVE		80
+
+struct multi_classes {
+  char *name;
+  int flag;
+} multi_class[] = {
+  { "mage"	, MULTI_MAGIC_USER	},
+  { "cleric"	, MULTI_CLERIC		},
+  { "thief"	, MULTI_THIEF		},
+  { "warrior"	, MULTI_WARRIOR		},
+  /* Insert new classes here 		*/
+  { "\n"	, 0			}
+};
+
+/* Multi message - modify this message to set multi message */
+char *multi_message = 
+"You have multied, and must begin anew. However, you will retain knowledge\r\n"
+"of your previous skills and spells, you just will not be able to use them\r\n"
+"until you reach the appropriate level.\r\n";
+
+/* END CUSTOMIZABLE OPTIONS 
+ *
+ * Only modify code below this point if you know what you are doing. It is set
+ * up however, so that if you are a newbie coder, but want a functional multi
+ * system, you will not have to modify ANYTHING below here.
+ *
+ */
+
+#define MULTI_NAME(i)		(multi_class[i].name)
+#define MULTI_FLAG(i)		(multi_class[i].flag)
+
+/* Will parse multi_class for proper passed argument */
+int find_multi_flag(char *arg)
+{
+  int i;
+
+  for (i = 0; *MULTI_NAME(i) != '\n'; i++)
+    if (is_abbrev(arg, MULTI_NAME(i)))
+      return i;
+
+  return -1;
+}
+
+int okay_to_multi(struct char_data * ch, int flag)
+{
+  int room;
+
+  /* Is wanted class same as current class? */
+  if (flag == GET_CLASS(ch)) {
+    sprintf(buf, "You are currently a %s!\r\n", pc_class_types[(int)GET_CLASS(ch)]);
+    send_to_char(buf, ch);
+    return FALSE;
+  }
+
+  /* Has char already completed this class? */
+  if (MULTI_FLAGGED(ch, MULTI_FLAG(flag))) {
+    send_to_char("You can not repeat a class already completed.\r\n", ch);
+    return FALSE;
+  }
+
+  if (GET_LEVEL(ch) < MULTI_LEVEL) {
+    sprintf(buf, "You are only level %d, you must be at least Level %d before you can multi.\r\n",
+		GET_LEVEL(ch), MULTI_LEVEL);
+    send_to_char(buf, ch);
+    return FALSE;
+  }
+
+  /* Is the char in the appropriate room? */
+  if (MULTI_ROOM >= 0) {
+    room = real_room(MULTI_ROOM);
+    if (room >= 0 && ch->in_room != room) {
+      send_to_char("You are not in the correct room to multi!\r\n", ch);
+      return FALSE;
+    }
+  }
+
+  /* Everything else is okay, return TRUE! */
+  return TRUE;
+}
+
+void reset_char_stats(struct char_data * ch, int flag)
+{
+  GET_MAX_HIT(ch) = MULTI_HP;
+  GET_MAX_MANA(ch) = MULTI_MANA;
+  GET_MAX_MOVE(ch) = MULTI_MOVE;
+ 
+  GET_HIT(ch) = GET_MAX_HIT(ch);
+  GET_MOVE(ch) = GET_MAX_MOVE(ch);
+  GET_MANA(ch) = GET_MAX_MANA(ch);
+
+  GET_LEVEL(ch) = 1;
+  GET_CLASS(ch) = flag;
+  GET_EXP(ch) = 1;
+  SET_BIT(MULTI_FLAGS(ch), MULTI_FLAG(flag));
+  GET_TOT_LEVEL(ch)++;
+
+  send_to_char(multi_message, ch);
+}
+
+ACMD(do_multi)
+{
+  int flag;
+
+  one_argument(argument, arg);
+
+  if (!*arg) {
+    send_to_char("Usage: multi <class name>\r\n", ch);
+    return;
+  }
+
+  if ((flag = find_multi_flag(arg)) < 0) {
+    send_to_char("Improper class name, please try again.\r\n", ch);
+    return;
+  }
+
+  if (!okay_to_multi(ch, flag))
+    return;
+
+  reset_char_stats(ch, flag);
+}
diff -uprN -x *.o circle30bpl12/src/spell_parser.c multi/src/spell_parser.c
--- circle30bpl12/src/spell_parser.c	Tue Oct 28 15:16:30 1997
+++ multi/src/spell_parser.c	Wed Dec  3 05:41:19 1997
@@ -617,6 +617,7 @@ ACMD(do_cast)
   struct obj_data *tobj = NULL;
   char *s, *t;
   int mana, spellnum, i, target = 0;
+  int class = 0;
 
   if (IS_NPC(ch))
     return;
@@ -650,6 +651,15 @@ ACMD(do_cast)
     send_to_char("You are unfamiliar with that spell.\r\n", ch);
     return;
   }
+  if (GET_SKILL(ch, spellnum)) {
+    for (class = 0; class < NUM_CLASSES; class++) {
+      if (GET_LEVEL(ch) < SINFO.min_level[class]) {
+  	send_to_char("Your level is not sufficient right now to cast that!\r\n", ch);
+        return;
+      }
+    }
+  }
+
   /* Find the target */
   if (t != NULL) {
     one_argument(strcpy(arg, t), t);
diff -uprN -x *.o circle30bpl12/src/structs.h multi/src/structs.h
--- circle30bpl12/src/structs.h	Tue Oct 28 15:16:30 1997
+++ multi/src/structs.h	Wed Dec  3 05:48:59 1997
@@ -742,8 +742,8 @@ struct player_special_data_saved {
    ubyte spare4;
    ubyte spare5;
    int spells_to_learn;		/* How many can you learn yet this level*/
-   int spare7;
-   int spare8;
+   int multi_flags;
+   int total_level;
    int spare9;
    int spare10;
    int spare11;
diff -uprN -x *.o circle30bpl12/src/utils.h multi/src/utils.h
--- circle30bpl12/src/utils.h	Wed Oct 29 07:04:08 1997
+++ multi/src/utils.h	Wed Dec  3 05:49:37 1997
@@ -168,6 +168,8 @@ void	update_pos(struct char_data *victim
 #define AFF_FLAGS(ch) ((ch)->char_specials.saved.affected_by)
 #define ROOM_FLAGS(loc) (world[(loc)].room_flags)
 
+#define MULTI_FLAGS(ch) ((ch)->player_specials->saved.multi_flags)
+
 #define IS_NPC(ch)  (IS_SET(MOB_FLAGS(ch), MOB_ISNPC))
 #define IS_MOB(ch)  (IS_NPC(ch) && ((ch)->nr >-1))
 
@@ -177,6 +179,8 @@ void	update_pos(struct char_data *victim
 #define PRF_FLAGGED(ch, flag) (IS_SET(PRF_FLAGS(ch), (flag)))
 #define ROOM_FLAGGED(loc, flag) (IS_SET(ROOM_FLAGS(loc), (flag)))
 
+#define MULTI_FLAGGED(ch, flag) (IS_SET(MULTI_FLAGS(ch), (flag)))
+
 /* IS_AFFECTED for backwards compatibility */
 #define IS_AFFECTED(ch, skill) (AFF_FLAGGED((ch), (skill)))
 
@@ -213,6 +217,8 @@ void	update_pos(struct char_data *victim
 #define GET_LEVEL(ch)   ((ch)->player.level)
 #define GET_PASSWD(ch)	((ch)->player.passwd)
 #define GET_PFILEPOS(ch)((ch)->pfilepos)
+
+#define GET_TOT_LEVEL(ch) ((ch)->player_specials->saved.total_level)
 
 /*
  * I wonder if this definition of GET_REAL_LEVEL should be the definition
