1stMUD/corefiles/
1stMUD/gods/
1stMUD/player/
1stMUD/win32/
1stMUD/win32/ROM/
diff -ur src/act_comm.c new/act_comm.c
--- src/act_comm.c	Fri Feb 21 23:16:36 2003
+++ new/act_comm.c	Fri Feb 21 23:27:59 2003
@@ -120,7 +120,7 @@
 	return TRUE;
 }
 
-void channel_social(CHAR_DATA * ch, CHAR_DATA * victim, OBJ_DATA * obj,
+void channel_social(CHAR_DATA * ch, CHAR_DATA * victim,
 					flag_t bit, const char *string, const char *type,
 					enum special_flags spec_flag)
 {
@@ -141,7 +141,7 @@
 			char buf[MSL];
 
 			sprintf(buf, "%s %s", type, string);
-			perform_act(buf, ch, obj, victim, FALSE, vch);
+			perform_act(buf, ch, NULL, victim, FALSE, vch);
 		}
 	}
 }
@@ -232,7 +232,7 @@
 			{
 				sprintf(buf, "%s %s", type, social_table[cmd].char_no_arg);
 				act_new(buf, ch, NULL, NULL, TO_CHAR, POS_DEAD);
-				channel_social(ch, NULL, NULL, bitname,
+				channel_social(ch, NULL, bitname,
 							   social_table[cmd].others_no_arg, type,
 							   spec_flag);
 			}
@@ -252,7 +252,7 @@
 				{
 					sprintf(buf, "%s %s", type, social_table[cmd].char_auto);
 					act_new(buf, ch, NULL, NULL, TO_CHAR, POS_DEAD);
-					channel_social(ch, victim, NULL, bitname,
+					channel_social(ch, victim, bitname,
 								   social_table[cmd].others_auto, type,
 								   spec_flag);
 				}
@@ -268,7 +268,7 @@
 								social_table[cmd].vict_found);
 						act_new(buf, ch, NULL, victim, TO_VICT, POS_DEAD);
 					}
-					channel_social(ch, victim, NULL, bitname,
+					channel_social(ch, victim, bitname,
 								   social_table[cmd].others_found, type,
 								   spec_flag);
 				}
@@ -358,6 +358,12 @@
 	else
 		chprintln(ch, "OFF");
 
+	chprint(ch, "ooc            ");
+	if (!IS_SET(ch->comm, COMM_NOOOC))
+		chprintln(ch, "ON");
+	else
+		chprintln(ch, "OFF");
+
 	chprint(ch, "auction        ");
 	if (!IS_SET(ch->comm, COMM_NOAUCTION))
 		chprintln(ch, "ON");
@@ -415,12 +421,6 @@
 	else
 		chprintln(ch, "OFF");
 
-	chprint(ch, "gocials        ");
-	if (IS_SET(ch->comm, COMM_NOGOCIAL))
-		chprintln(ch, "OFF");
-	else
-		chprintln(ch, "ON");
-
 	if (IS_SET(ch->comm, COMM_AFK))
 		chprintln(ch, "You are AFK.");
 
@@ -453,6 +453,9 @@
 
 	if (IS_SET(ch->comm, COMM_NOEMOTE))
 		chprintln(ch, "You cannot show emotions.");
+
+	if (IS_SET(ch->comm, COMM_NOGOCIAL))
+		chprintln(ch, "You cannot see socials/emotes over public channels.");
 
 }
 
diff -ur src/act_info.c new/act_info.c
--- src/act_info.c	Fri Feb 21 23:16:36 2003
+++ new/act_info.c	Fri Feb 21 23:27:59 2003
@@ -265,7 +265,7 @@
 		strcat(buf, "(Golden Aura) ");
 	if (IS_AFFECTED(victim, AFF_SANCTUARY))
 		strcat(buf, "(White Aura) ");
-	if (IS_SET(victim->act, PLR_WAR))
+	if (!IS_NPC(victim) && IS_SET(victim->act, PLR_WAR))
 		strcat(buf, "(WAR) ");
 	if (!IS_NPC(victim) && IS_SET(victim->act, PLR_KILLER))
 		strcat(buf, "(KILLER) ");
@@ -1511,18 +1511,20 @@
 			   CTAG(_SCORE1) " gold and " CTAG(_SCORE2) "%ld"
 			   CTAG(_SCORE1) " silver coins.{x", ch->exp, ch->gold, ch->silver);
 
-	chprintlnf(ch,
-			   "" CTAG(_SCORE1) "You have " CTAG(_SCORE2) "%ld"
-			   CTAG(_SCORE1) " gold and " CTAG(_SCORE2) "%ld"
-			   CTAG(_SCORE1) " silver in you bank account.{x",
-			   ch->pcdata->gold_bank, ch->pcdata->silver_bank);
-
-	chprintlnf(ch,
-			   "" CTAG(_SCORE1) "You have earned " CTAG(_SCORE2) "%d"
-			   CTAG(_SCORE1) " questpoints and " CTAG(_SCORE2) "%d"
-			   CTAG(_SCORE1) " trivia points.{x", ch->pcdata->questpoints,
-			   ch->pcdata->trivia);
+	if (!IS_NPC(ch))
+	{
+		chprintlnf(ch,
+				   "" CTAG(_SCORE1) "You have " CTAG(_SCORE2) "%ld"
+				   CTAG(_SCORE1) " gold and " CTAG(_SCORE2) "%ld"
+				   CTAG(_SCORE1) " silver in you bank account.{x",
+				   ch->pcdata->gold_bank, ch->pcdata->silver_bank);
 
+		chprintlnf(ch,
+				   "" CTAG(_SCORE1) "You have earned " CTAG(_SCORE2) "%d"
+				   CTAG(_SCORE1) " questpoints and " CTAG(_SCORE2) "%d"
+				   CTAG(_SCORE1) " trivia points.{x", ch->pcdata->questpoints,
+				   ch->pcdata->trivia);
+	}
 	chprintlnf(ch,
 			   "" CTAG(_SCORE2) "You worship " CTAG(_SCORE2) "%s, %s"
 			   CTAG(_SCORE1) ".{x",
@@ -2082,12 +2084,12 @@
 	 * Format it up.
 	 */
 	if (wch->pcdata->who_descr[0] != '\0' && wch->pcdata->who_descr != NULL)
-		sprintf(block, "[%-14s] ", wch->pcdata->who_descr);
+		sprintf(block, "[%s] ",
+				stringf(14, ALIGN_CENTER, NULL, wch->pcdata->who_descr));
 	else
 		sprintf(block,
-				"[" CTAG(_WLEVEL) "%03d " CTAG(_WRACE) "%6s "
-				CTAG(_WCLASS) "%s{x] ", wch->level,
-				race_table[wch->race].who_name, Class);
+				"[" CTAG(_WLEVEL) "%03d " CTAG(_WRACE) "%6s " CTAG(_WCLASS)
+				"%s{x] ", wch->level, race_table[wch->race].who_name, Class);
 
 	sprintf(buf, "%s%s%s%s%s%s%s%s%s%s%s%s\n\r", block,
 			format_clan(wch),
@@ -2237,6 +2239,12 @@
 	return;
 }
 
+struct s_charitem
+{
+	CHAR_DATA *pch;
+	long levelkey;
+};
+
 /*
  * New 'who' command originally by Alander of Rivers of Mud.
  */
@@ -2252,7 +2260,8 @@
 	int iLevelLower;
 	int iLevelUpper;
 	int nNumber;
-	int nMatch;
+	int nMatch, count = 0, immcount = 0;
+	int ndesc, totalcount = 0, imminvis = 0;
 	bool *rgfClass;
 	bool *rgfRace;
 	bool *rgfClan;
@@ -2261,6 +2270,10 @@
 	bool fClan = FALSE;
 	bool fRaceRestrict = FALSE;
 	bool fImmortalOnly = FALSE;
+	struct s_charitem *charitems, tmp_charitem;
+	bool searched = FALSE;
+	int j1, j2;
+	CHAR_DATA *wch;
 
 	/*
 	 * Set default arguments.
@@ -2288,6 +2301,8 @@
 		argument = one_argument(argument, arg);
 		if (arg[0] == '\0')
 			break;
+		else
+			searched = TRUE;
 
 		if (is_number(arg))
 		{
@@ -2364,27 +2379,45 @@
 		}
 	}
 
+	ndesc = 0;
+	for (d = descriptor_first; d != NULL; d = d->next)
+		ndesc++;
+
+	alloc_mem(charitems, struct s_charitem, ndesc);
+
+	if (ndesc > max_on)
+		max_on = ndesc;
+
 	/*
 	 * Now show matching chars.
 	 */
 	nMatch = 0;
 	buf[0] = '\0';
 	output = new_buf();
+	add_buf(output, draw_line("{r-{R-", 0));
+	add_buf(output, "\n\r");
 	for (d = descriptor_first; d != NULL; d = d->next)
 	{
-		CHAR_DATA *wch;
-
 		/*
 		 * Check for match against restrictions.
 		 * Don't use trust as that exposes trusted mortals.
 		 */
-		if (d->connected != CON_PLAYING || !can_see(ch, d->character))
+		if (d->connected != CON_PLAYING)
 			continue;
 
 		wch = (d->original != NULL) ? d->original : d->character;
 
+		if (get_trust(wch) >= LEVEL_IMMORTAL && wch->level >= LEVEL_IMMORTAL)
+			immcount++;
+		else
+			count++;
+
 		if (!can_see(ch, wch))
+		{
+			if (IS_IMMORTAL(wch))
+				imminvis++;
 			continue;
+		}
 
 		if (wch->level < iLevelLower || wch->level > iLevelUpper ||
 			(fImmortalOnly && wch->level < LEVEL_IMMORTAL) ||
@@ -2396,13 +2429,62 @@
 											&& !rgfClan[wch->clan]))
 			continue;
 
+		charitems[nMatch].pch = wch;
+		charitems[nMatch].levelkey = wch->level + 1;
 		nMatch++;
+	}
+
+	totalcount = (count + immcount);
 
+	for (j1 = 0; j1 < nMatch - 1; j1++)
+	{
+		for (j2 = j1 + 1; j2 < nMatch; j2++)
+		{
+			if (charitems[j2].levelkey > charitems[j1].levelkey)
+			{
+				tmp_charitem = charitems[j1];
+				charitems[j1] = charitems[j2];
+				charitems[j2] = tmp_charitem;
+			}
+		}
+	}
+
+	for (j1 = 0; j1 < nMatch; j1++)
+	{
+		wch = charitems[j1].pch;
 		add_buf(output, format_who(ch, wch));
+		if (j1 == (immcount - imminvis - 1) && j1 != (nMatch - 1)
+			&& IS_IMMORTAL(wch))
+		{
+			add_buf(output, draw_line("{r-{R-", 0));
+			add_buf(output, "\n\r");
+		}
+	}
+
+	free_mem(charitems);
+
+	add_buf(output, draw_line("{r-{R-", 0));
+	add_buf(output, "\n\r");
+
+	if (searched)
+	{
+		sprintf(buf2, "{WMatches found: {R%d{x\n\r", nMatch);
+		add_buf(output, buf2);
+	}
+	else if (nMatch < (totalcount - imminvis))
+	{
+		sprintf(buf2,
+				"{WPlayers found: {R%d{W  Most since boot: {R%d{W  Invisible: {R%d{x\n\r",
+				nMatch, max_on, (totalcount - nMatch - imminvis));
+		add_buf(output, buf2);
+	}
+	else
+	{
+		sprintf(buf2, "{WPlayers found: {R%d{W  Most since boot: {R%d{x\n\r",
+				totalcount - imminvis, max_on);
+		add_buf(output, buf2);
 	}
 
-	sprintf(buf2, "\n\rPlayers found: %d\n\r", nMatch);
-	add_buf(output, buf2);
 	if (!ON_GQUEST(ch) && gquest_info.minlevel < ch->level &&
 		gquest_info.maxlevel > ch->level)
 		add_buf(output, "There is a Global Quest running you can join.\n\r");
diff -ur src/act_wiz.c new/act_wiz.c
--- src/act_wiz.c	Fri Feb 21 23:16:36 2003
+++ new/act_wiz.c	Fri Feb 21 23:28:00 2003
@@ -47,6 +47,7 @@
 #include "../win32/winstuff.h"
 #endif
 #include "webserver.h"
+#include "magic.h"
 
 /*
  * Local functions.
@@ -4391,8 +4392,6 @@
 /* This is the executable file */
 #define EXE_FILE	  "../src/rom"
 
-bool write_to_descriptor args((DESCRIPTOR_DATA * d, char *txt, int length));
-
 /*  Copyover - Original idea: Fusion of MUD++
  *  Adapted to Diku by Erwin S. Andreasen, <erwin@andreasen.org>
  *  http://www.andreasen.org
@@ -4582,4 +4581,205 @@
 	}
 	file_close(fp);
 
+}
+
+struct qspell_type
+{
+	SPELL_FUN *spellf;
+};
+
+int sn_spellfun_lookup(SPELL_FUN * fun)
+{
+	int sn;
+
+	for (sn = 0; sn < maxSkill; sn++)
+	{
+		if (skill_table[sn].spell_fun == fun)
+			return sn;
+	}
+	return -1;
+}
+
+const struct qspell_type qspell_table[] = {
+	{spell_bless},
+	{spell_giant_strength},
+	{spell_haste},
+	{spell_frenzy},
+	{spell_shield},
+	{spell_armor},
+	{spell_sanctuary},
+	{spell_detect_hidden},
+	{spell_detect_invis},
+	{spell_stone_skin},
+	{NULL},
+};
+
+CH_CMD(do_spellup)
+{
+	CHAR_DATA *vch;
+	char arg[MIL];
+	DESCRIPTOR_DATA *tempdesc;
+	int i, sn;
+
+	argument = one_argument(argument, arg);
+
+	if (IS_NULLSTR(arg))
+	{
+		chprintln(ch, "Syntax: spellup [all, room, <char>]");
+		return;
+	}
+
+	if (!str_cmp(arg, "all"))
+	{
+		tempdesc = ch->desc;
+		ch->desc = NULL;
+		for (vch = player_first; vch != NULL; vch = vch->next_player)
+		{
+			if (vch == ch || !can_see(ch, vch))
+				continue;
+
+			do_function(ch, &do_spellup, vch->name);
+		}
+		ch->desc = tempdesc;
+		chprintln(ch, "OK.");
+	}
+	else if (!str_cmp(arg, "room"))
+	{
+		//Lets not spam the caster out
+		tempdesc = ch->desc;
+		ch->desc = NULL;
+		for (vch = ch->in_room->first_person; vch; vch = vch->next_in_room)
+		{
+			if (vch == ch || IS_NPC(vch) || !can_see(ch, vch))
+				continue;
+
+			do_function(ch, &do_spellup, vch->name);
+		}
+		ch->desc = tempdesc;
+		chprintln(ch, "OK.");
+	}
+	else if ((vch = get_char_world(ch, arg)) != NULL)
+	{
+		//Lets not spam the caster out
+		tempdesc = ch->desc;
+		ch->desc = NULL;
+		for (i = 0, sn = 0; qspell_table[i].spellf != NULL; i++)
+		{
+			sn = sn_spellfun_lookup(qspell_table[i].spellf);
+			if (sn == -1)
+				continue;
+			if (is_affected(vch, sn))
+				continue;
+			qspell_table[i].spellf(sn, get_trust(ch), ch, vch, TARGET_CHAR);
+		}
+		ch->desc = tempdesc;
+		chprintln(ch, "OK.");
+	}
+	else
+		chprintln(ch, "Syntax: spellup [all, room, <char>]");
+
+	return;
+}
+
+/** Function: do_pload
+  * Descr   : Loads a player object into the mud, bringing them (and their
+  *           pet) to you for easy modification.  Player must not be connected.
+  *           Note: be sure to send them back when your done with them.
+  * Returns : (void)
+  * Syntax  : pload (who)
+  * Written : v1.0 12/97
+  * Author  : Gary McNickle <gary@dharvest.com>
+  */
+CH_CMD(do_pload)
+{
+	DESCRIPTOR_DATA d;
+	bool isChar = FALSE;
+	char name[MAX_INPUT_LENGTH];
+
+	if (argument[0] == '\0')
+	{
+		chprintln(ch, "Load who?");
+		return;
+	}
+
+	argument = one_argument(argument, name);
+
+	/* Dont want to load a second copy of a player who's allready online! */
+	if (get_char_world(ch, name) != NULL)
+	{
+		chprintln(ch, "That person is already connected!");
+		return;
+	}
+
+	isChar = load_char_obj(&d, capitalize(name));	/* char pfile exists? */
+
+	if (!isChar)
+	{
+		chprintln(ch, "Load Who? Are you sure? I cant seem to find them.");
+		return;
+	}
+
+	d.character->desc = NULL;
+	LINK(d.character, char_first, char_last, next, prev);
+	LINK(d.character, player_first, player_last, next_player, prev_player);
+	d.connected = CON_PLAYING;
+	reset_char(d.character);
+
+	/* bring player to imm */
+	if (d.character->in_room != NULL)
+	{
+		char_to_room(d.character, ch->in_room);	/* put in room imm is in */
+	}
+
+	act("$n has pulled $N from the pattern!", ch, NULL, d.character, TO_ROOM);
+
+	if (d.character->pet != NULL)
+	{
+		char_to_room(d.character->pet, d.character->in_room);
+		act("$n has entered the game.", d.character->pet, NULL, NULL, TO_ROOM);
+	}
+
+}
+
+/** Function: do_punload
+  * Descr   : Returns a player, previously 'ploaded' back to the void from
+  *           whence they came.  This does not work if the player is actually 
+  *           connected.
+  * Returns : (void)
+  * Syntax  : punload (who)
+  * Written : v1.0 12/97
+  * Author  : Gary McNickle <gary@dharvest.com>
+  */
+CH_CMD(do_punload)
+{
+	CHAR_DATA *victim;
+	char who[MAX_INPUT_LENGTH];
+
+	argument = one_argument(argument, who);
+
+	if ((victim = get_char_world(ch, who)) == NULL)
+	{
+		chprintln(ch, "They aren't here.");
+		return;
+	}
+
+  /** Person is legitametly logged on... was not ploaded.
+   */
+	if (victim->desc != NULL)
+	{
+		chprintln(ch, "I dont think that would be a good idea...");
+		return;
+	}
+
+	if (victim->was_in_room != NULL)	/* return player and pet to orig room */
+	{
+		char_to_room(victim, victim->was_in_room);
+		if (victim->pet != NULL)
+			char_to_room(victim->pet, victim->was_in_room);
+	}
+
+	save_char_obj(victim);
+	do_quit(victim, "");
+
+	act("$n has released $N back to the Pattern.", ch, NULL, victim, TO_ROOM);
 }
diff -ur src/board.c new/board.c
--- src/board.c	Fri Feb 21 23:16:36 2003
+++ new/board.c	Fri Feb 21 23:28:00 2003
@@ -172,8 +172,8 @@
 		last_note_stamp = current_time;
 	}
 
-	if (board->note_first)		/* are there any notes in there now? */
-		LINK(note, board->note_first, board->note_last, next, prev);
+	LINK(note, board->note_first, board->note_last, next, prev);
+
 	/* append note to note file */
 
 	sprintf(filename, "%s%s", NOTE_DIR, board->short_name);
@@ -535,10 +535,11 @@
 		chprintln(ch, "{GYour note so far:{x");
 		chprint(ch, ch->pcdata->in_progress->text);
 
-		chprintln
+		chprintlnf
 			(ch,
-			 "\n\rEnter text. Type {W.q{x or {W@{x on an empty line to end note, or {W.h{x for help.\n\r"
-			 "======================================================================");
+			 "\n\rEnter text. Type {W%cq{x or {W@{x on an empty line to end note, or {W%ch{x for help.\n\r"
+			 "======================================================================",
+			 STR_EDIT_KEY(ch), STR_EDIT_KEY(ch));
 
 		ch->desc->connected = CON_NOTE_TEXT;
 
@@ -1010,10 +1011,11 @@
 			sprintf(buf, "This note will expire %s\r",
 					ctime(&ch->pcdata->in_progress->expire));
 			write_to_buffer(d, buf, 0);
-			write_to_buffer(d,
-							"\n\rEnter text. Type {W.q{x or {W@{x on an empty line to end note, or {W.h{x for help.\n\r"
-							"======================================================================\n\r",
-							0);
+			sprintf(buf,
+					"\n\rEnter text. Type {W%cq{x or {W@{x on an empty line to end note, or {W%ch{x for help.\n\r"
+					"======================================================================\n\r",
+					STR_EDIT_KEY(ch), STR_EDIT_KEY(ch));
+			write_to_buffer(d, buf, 0);
 			d->connected = CON_NOTE_TEXT;
 		}
 	}
@@ -1062,10 +1064,11 @@
 
 	/* note that ctime returns XXX\n so we only need to add an \r */
 
-	write_to_buffer(d,
-					"\n\rEnter text. Type {W.q{x or {W@{x on an empty line to end note, or {W.h{x for help.\n\r"
-					"======================================================================",
-					0);
+	sprintf(buf,
+			"\n\rEnter text. Type {W%cq{x or {W@{x on an empty line to end note, or {W%ch{x for help.\n\r"
+			"======================================================================",
+			STR_EDIT_KEY(ch), STR_EDIT_KEY(ch));
+	write_to_buffer(d, buf, 0);
 	d->connected = CON_NOTE_TEXT;
 }
 
diff -ur src/comm.c new/comm.c
--- src/comm.c	Fri Feb 21 23:16:36 2003
+++ new/comm.c	Fri Feb 21 23:28:00 2003
@@ -100,7 +100,6 @@
 int init_socket args((int prt));
 void init_descriptor args((int ctrl));
 bool read_from_descriptor args((DESCRIPTOR_DATA * d));
-bool write_to_descriptor args((DESCRIPTOR_DATA * d, char *txt, int length));
 void halt_mud args((int sig));
 
 /*
diff -ur src/db.c new/db.c
--- src/db.c	Fri Feb 21 23:16:37 2003
+++ new/db.c	Fri Feb 21 23:28:00 2003
@@ -343,6 +343,8 @@
 		load_bank_data();
 		log_string("Loading deities...");
 		load_deities();
+		log_string("Loading web passwords...");
+		load_webpasses();
 	}
 
 	return;
diff -ur src/dofun.h new/dofun.h
--- src/dofun.h	Fri Feb 21 23:16:37 2003
+++ new/dofun.h	Fri Feb 21 23:28:00 2003
@@ -315,5 +315,11 @@
 COMMAND_FUN (do_dedit)
 COMMAND_FUN (do_nogocial)
 COMMAND_FUN (do_ooc)
+COMMAND_FUN (do_webpass)
+COMMAND_FUN (do_spellup)
+COMMAND_FUN (do_strkey)
+COMMAND_FUN (do_run)
+COMMAND_FUN (do_pload)
+COMMAND_FUN (do_punload)
 
 // *INDENT-ON*
diff -ur src/globals.h new/globals.h
--- src/globals.h	Fri Feb 21 23:16:37 2003
+++ new/globals.h	Fri Feb 21 23:28:00 2003
@@ -121,4 +121,7 @@
 GLOBAL_DEF(int maxDeity, 1);
 GLOBAL_DEF(struct deity_type *deity_table, NULL);
 
+GLOBAL_DEF(WPWD_DATA * wpwd_first, NULL);
+GLOBAL_DEF(WPWD_DATA * wpwd_last, NULL);
+
 #endif
diff -ur src/mccp.c new/mccp.c
--- src/mccp.c	Fri Feb 21 23:16:37 2003
+++ new/mccp.c	Fri Feb 21 23:28:00 2003
@@ -59,7 +59,6 @@
 char compress_start[] = { IAC, SB, TELOPT_COMPRESS, WILL, SE, '\0' };
 
 bool processCompressed(DESCRIPTOR_DATA * desc);
-bool write_to_descriptor args((DESCRIPTOR_DATA * d, char *txt, int length));
 
 /*
  * Memory management - zlib uses these hooks to allocate and free memory
diff -ur src/mem.c new/mem.c
--- src/mem.c	Fri Feb 21 23:16:37 2003
+++ new/mem.c	Fri Feb 21 23:28:00 2003
@@ -99,10 +99,10 @@
 	pArea->max_vnum = 0;
 	pArea->age = 0;
 	pArea->nplayer = 0;
+	pArea->vnum = top_area;
 	pArea->empty = TRUE;		/* ROM patch */
 	sprintf(buf, "area%d.are", pArea->vnum);
 	pArea->file_name = str_dup(buf);
-	pArea->vnum = top_area - 1;
 
 	return pArea;
 }
diff -ur src/merc.h new/merc.h
--- src/merc.h	Fri Feb 21 23:16:37 2003
+++ new/merc.h	Fri Feb 21 23:28:00 2003
@@ -146,6 +146,7 @@
 typedef struct auction_data AUCTION_DATA;
 typedef struct clan_rank RANK_DATA;
 typedef struct deity_type DEITY_DATA;
+typedef struct wpwd_data WPWD_DATA;
 
 /*
  * Function types.
@@ -1456,6 +1457,15 @@
 	int next;
 };
 
+struct wpwd_data
+{
+	WPWD_DATA *next;
+	WPWD_DATA *prev;
+	bool valid;
+	const char *name;
+	const char *passw;
+};
+
 #define INFO_ALL        (BIT_A)
 #define INFO_QUIET      (BIT_B)
 #define INFO_LOGIN      (BIT_C)
@@ -1716,6 +1726,8 @@
 	long gold_bank;
 	long silver_bank;
 	int shares;
+	const char *webpass;
+	char str_ed_key;
 };
 
 /* Data for generating characters -- only used during generation */
@@ -2271,6 +2283,8 @@
 
 #define	ON_GQUEST(ch)      (!IS_NPC(ch) && IS_SET((ch)->act, PLR_GQUEST) && gquest_info.running != GQUEST_OFF)
 
+#define STR_EDIT_KEY(ch) (IS_NPC(ch) ? '.' : ch->pcdata->str_ed_key)
+
 /*
  * Object macros.
  */
@@ -2383,6 +2397,7 @@
 #define PIT_FILE        DATA_DIR "pit.dat"
 #define BANK_FILE       DATA_DIR "bank.dat"
 #define DEITY_FILE      DATA_DIR "deity.dat"
+#define WPWD_FILE       DATA_DIR "webpass.dat"
 
 #include "proto.h"
 
diff -ur src/multiclass.c new/multiclass.c
--- src/multiclass.c	Fri Feb 21 23:16:37 2003
+++ new/multiclass.c	Fri Feb 21 23:28:00 2003
@@ -424,8 +424,12 @@
 		return 2;
 
 	for (iClass = 0; ch->Class[iClass] != -1; iClass++)
-		temprate = UMIN(temprate, skill_table[sn].rating[ch->Class[iClass]]);
+	{
+		if (skill_table[sn].rating[ch->Class[iClass]] < 1)
+			continue;
 
+		temprate = UMIN(temprate, skill_table[sn].rating[ch->Class[iClass]]);
+	}
 	return temprate == 999 ? 0 : temprate;
 }
 
@@ -446,8 +450,12 @@
 		return 2;
 
 	for (iClass = 0; ch->Class[iClass] != -1; iClass++)
-		temprate = UMIN(temprate, group_table[gn].rating[ch->Class[iClass]]);
+	{
+		if (group_table[gn].rating[ch->Class[iClass]] < 1)
+			continue;
 
+		temprate = UMIN(temprate, group_table[gn].rating[ch->Class[iClass]]);
+	}
 	return temprate == 999 ? 0 : temprate;
 }
 
diff -ur src/olc.c new/olc.c
--- src/olc.c	Fri Feb 21 23:16:37 2003
+++ new/olc.c	Fri Feb 21 23:28:00 2003
@@ -211,7 +211,7 @@
 		sprintf(buf, "object");
 		break;
 	case ED_MOBILE:
-		sprintf(buf, "mobile ");
+		sprintf(buf, "mobile");
 		break;
 	case ED_MPCODE:
 		sprintf(buf, "mobile program");
@@ -247,7 +247,7 @@
 		sprintf(buf, "class");
 		break;
 	case ED_DEITY:
-		return "deity";
+		sprintf(buf, "deity");
 		break;
 	default:
 		break;
diff -ur src/proto.h new/proto.h
--- src/proto.h	Fri Feb 21 23:16:37 2003
+++ new/proto.h	Fri Feb 21 23:28:00 2003
@@ -543,6 +543,12 @@
 void load_deities args((void));
 void save_deities args((void));
 
+void update_webpasses args((CHAR_DATA * ch, bool pDelete));
+void save_webpasses args((void));
+void load_webpasses args((void));
+
+bool write_to_descriptor args((DESCRIPTOR_DATA * d, char *txt, int length));
+
 #undef	CD
 #undef	MID
 #undef	OD
diff -ur src/recycle.c new/recycle.c
--- src/recycle.c	Fri Feb 21 23:16:37 2003
+++ new/recycle.c	Fri Feb 21 23:28:00 2003
@@ -324,6 +324,7 @@
 	pcdata->buffer = new_buf();
 	alloc_mem(pcdata->learned, int, maxSkill);
 	alloc_mem(pcdata->group_known, bool, maxGroup);
+	pcdata->str_ed_key = '/';
 	VALIDATE(pcdata);
 	return pcdata;
 }
@@ -340,6 +341,7 @@
 	free_string(pcdata->bamfout);
 	free_string(pcdata->title);
 	free_string(pcdata->who_descr);
+	free_string(pcdata->webpass);
 	free_buf(pcdata->buffer);
 	free_mem(pcdata->learned);
 	free_mem(pcdata->group_known);
@@ -661,4 +663,32 @@
 	INVALIDATE(auction);
 
 	PUT_FREE(auction, next, auction_free);
+}
+
+WPWD_DATA *WPWD_free;
+
+WPWD_DATA *new_pwd(void)
+{
+	static WPWD_DATA WPWD_zero;
+	WPWD_DATA *pwd;
+
+	GET_FREE(pwd, WPWD_DATA, next, WPWD_free);
+
+	*pwd = WPWD_zero;
+	pwd->name = &str_empty[0];
+	pwd->passw = &str_empty[0];
+	VALIDATE(pwd);
+	return pwd;
+}
+
+void free_pwd(WPWD_DATA * pwd)
+{
+	if (!IS_VALID(pwd))
+		return;
+
+	free_string(pwd->name);
+	free_string(pwd->passw);
+	INVALIDATE(pwd);
+
+	PUT_FREE(pwd, next, WPWD_free);
 }
diff -ur src/recycle.h new/recycle.h
--- src/recycle.h	Fri Feb 21 23:16:37 2003
+++ new/recycle.h	Fri Feb 21 23:28:00 2003
@@ -141,4 +141,7 @@
 AUCTION_DATA *new_auction args((void));
 void free_auction args((AUCTION_DATA * auction));
 
+void free_pwd args((WPWD_DATA * pwd));
+WPWD_DATA *new_pwd args((void));
+
 #endif
diff -ur src/save.c new/save.c
--- src/save.c	Fri Feb 21 23:16:37 2003
+++ new/save.c	Fri Feb 21 23:28:00 2003
@@ -254,6 +254,9 @@
 		if (ch->pcdata->trivia != 0)
 			fprintf(fp, "Trivia  %d\n", ch->pcdata->trivia);
 
+		if (ch->pcdata->str_ed_key != '.' && ch->pcdata->str_ed_key != ' ')
+			fprintf(fp, "StrEdKey\t%c\n", ch->pcdata->str_ed_key);
+
 		if (ch->pcdata->awins != 0)
 			fprintf(fp, "AWins  %d\n", ch->pcdata->awins);
 
@@ -1223,6 +1226,7 @@
 			KEY("Sec", ch->pcdata->security, fread_number(fp));	/* OLC */
 			KEY("Silv", ch->silver, fread_number(fp));
 			KEY("Shares", ch->pcdata->shares, fread_number(fp));
+			KEY("StrEdKey", ch->pcdata->str_ed_key, fread_letter(fp));
 			if (!str_cmp(word, "StayRace"))
 			{
 				ch->pcdata->stay_race = TRUE;
diff -ur src/string.c new/string.c
--- src/string.c	Fri Feb 21 23:16:37 2003
+++ new/string.c	Fri Feb 21 23:28:00 2003
@@ -64,8 +64,9 @@
 void string_edit(CHAR_DATA * ch, const char **pString)
 {
 	chprintln(ch, "-========- Entering EDIT Mode -=========-");
-	chprintln(ch, "    Type .h on a new line for help");
-	chprintln(ch, " Terminate with a .q or @ on a blank line.");
+	chprintlnf(ch, "    Type %ch on a new line for help", STR_EDIT_KEY(ch));
+	chprintlnf(ch, " Terminate with a %cq or @ on a blank line.",
+			   STR_EDIT_KEY(ch));
 	chprintln(ch, "-=======================================-");
 
 	if (*pString == NULL)
@@ -90,8 +91,9 @@
 void string_append(CHAR_DATA * ch, const char **pString)
 {
 	chprintln(ch, "-=======- Entering APPEND Mode -========-");
-	chprintln(ch, "    Type .h on a new line for help");
-	chprintln(ch, " Terminate with a .q or @ on a blank line.");
+	chprintlnf(ch, "    Type %ch on a new line for help", STR_EDIT_KEY(ch));
+	chprintlnf(ch, " Terminate with a %cq or @ on a blank line.",
+			   STR_EDIT_KEY(ch));
 	chprintln(ch, "-=======================================-");
 
 	if (*pString == NULL)
@@ -205,22 +207,27 @@
 	case PARSE_HELP:
 		chprintln(ch,
 				  "-------------------------------------------------------");
-		chprintln(ch,
-				  "Edit help (commands on blank line):\n\r"
-				  ".h               - get help (this info)\n\r"
-				  ".s               - show string so far\n\r"
-				  ".S               - show string so far without line numbers\n\r"
-				  ".f               - formats text\n\r"
-				  ".c               - clear string so far\n\r"
-				  ".d#              - delete line number <num>\n\r"
-				  ".d               - delete last line\n\r"
-				  ".i# <str>        - insert <str> on line <num>\n\r"
-				  ".e# <str>        - replace line <num> with <str>\n\r"
-				  ".r 'a' 'b'       - replace first occurance of text\n\r"
-				  ".R 'a' 'b'       - replace all occurances of text\n\r"
-				  "                   usage: .r 'pattern' 'replacement'\n\r"
-				  ".| <command>     - execute a mud command\n\r"
-				  ".q               - end string");
+		chprintlnf(ch,
+				   "Edit help (commands on blank line):\n\r"
+				   "%ch               - get help (this info)\n\r"
+				   "%cs               - show string so far\n\r"
+				   "%cS               - show string so far without line numbers\n\r"
+				   "%cf               - formats text\n\r"
+				   "%cc               - clear string so far\n\r"
+				   "%cd#              - delete line number <num>\n\r"
+				   "%cd               - delete last line\n\r"
+				   "%ci# <str>        - insert <str> on line <num>\n\r"
+				   "%ce# <str>        - replace line <num> with <str>\n\r"
+				   "%cr 'a' 'b'       - replace first occurance of text\n\r"
+				   "%cR 'a' 'b'       - replace all occurances of text\n\r"
+				   "                   usage: %cr 'pattern' 'replacement'\n\r"
+				   "%c| <command>     - execute a mud command\n\r"
+				   "%cq               - end string", STR_EDIT_KEY(ch),
+				   STR_EDIT_KEY(ch), STR_EDIT_KEY(ch), STR_EDIT_KEY(ch),
+				   STR_EDIT_KEY(ch), STR_EDIT_KEY(ch), STR_EDIT_KEY(ch),
+				   STR_EDIT_KEY(ch), STR_EDIT_KEY(ch), STR_EDIT_KEY(ch),
+				   STR_EDIT_KEY(ch), STR_EDIT_KEY(ch), STR_EDIT_KEY(ch),
+				   STR_EDIT_KEY(ch));
 		chprintln(ch, "------------------------------------------------------");
 		break;
 	case PARSE_FORMAT:
@@ -293,7 +300,7 @@
 	int i = 2, j = 0;
 	char actions[MAX_INPUT_LENGTH];
 
-	if ((*str == '.'))
+	if ((*str == STR_EDIT_KEY(ch)))
 	{
 		while (str[i] != '\0')
 		{
@@ -1251,4 +1258,28 @@
 
 	strcat(result, lbuf);
 	return result;
+}
+
+CH_CMD(do_strkey)
+{
+	if (IS_NPC(ch))
+		return;
+
+	if (IS_NULLSTR(argument) || strlen(argument) > 1)
+	{
+		chprintln(ch, "Syntax: strkey <key>");
+		chprintln(ch, "Where <key> can be any 1 letter you want ");
+		chprintln(ch, "to use for string editor commands.");
+		return;
+	}
+
+	if (!isascii(argument[0]) || argument[0] == ' ' || argument[0] == '\\')
+	{
+		chprintln(ch, "Invalid string editor key.");
+		return;
+	}
+
+	ch->pcdata->str_ed_key = argument[0];
+	chprintlnf(ch, "The string editor now uses %c for commands.",
+			   STR_EDIT_KEY(ch));
 }
diff -ur src/tablesave.c new/tablesave.c
--- src/tablesave.c	Fri Feb 21 23:16:37 2003
+++ new/tablesave.c	Fri Feb 21 23:28:00 2003
@@ -79,6 +79,7 @@
 BAN_DATA ban;
 GQUEST gq;
 DEITY_DATA deity;
+WPWD_DATA pwd;
 
 const char *do_fun_name(DO_FUN *);
 DO_FUN *do_fun_lookup(const char *);
@@ -350,6 +351,12 @@
 	{NULL, 0, NULL, NULL, NULL}
 };
 
+const struct savetable_type pwdsavetable[] = {
+	{"name", FIELD_STRING, (void *) &pwd.name, NULL, NULL},
+	{"pwd", FIELD_STRING, (void *) &pwd.passw, NULL, NULL},
+	{NULL, 0, NULL, NULL, NULL}
+};
+
 void load_struct(FILE * fp, void *typebase,
 				 const struct savetable_type *table, void *puntero)
 {
@@ -723,8 +730,8 @@
 			fprintf(fp, "%s\t\t", temp->field);
 			for (i = 0;
 				 i <
-				 (temp->argument ? (int) temp->
-				  argument : *(int *) temp->argument2); i++)
+				 (temp->argument ? (int) temp->argument : *(int *) temp->
+				  argument2); i++)
 				fprintf(fp, "%d ", pbool[i] == TRUE ? 1 : 0);
 			fprintf(fp, "@\n");
 			break;
@@ -1639,5 +1646,74 @@
 
 	deity_table[maxDeity].name = NULL;
 
+	file_close(fp);
+}
+
+void save_webpasses(void)
+{
+	WPWD_DATA *ppwd;
+	FILE *fp;
+#if !defined(WIN32)
+	char *TEMPFILE = WPWD_FILE ".tmp";
+
+	if ((fp = file_open(TEMPFILE, "w")) == NULL)
+#else
+	if ((fp = file_open(WPWD_FILE, "w")) == NULL)
+#endif
+	{
+		perror(WPWD_FILE);
+		file_close(fp);
+		return;
+	}
+
+	for (ppwd = wpwd_first; ppwd != NULL; ppwd = ppwd->next)
+	{
+		fprintf(fp, "#WPWD\n");
+		save_struct(fp, &pwd, pwdsavetable, ppwd);
+		fprintf(fp, "#END\n\n");
+	}
+
+	fprintf(fp, "#!\n");
+
+	file_close(fp);
+
+#if !defined(WIN32)
+	rename(TEMPFILE, WPWD_FILE);
+#endif
+}
+
+void load_webpasses(void)
+{
+	FILE *fp;
+	WPWD_DATA *ppwd;
+	const char *word;
+
+	fp = file_open(WPWD_FILE, "r");
+
+	if (!fp)
+	{
+		bug("Unable to open " WPWD_FILE " to load pwdlist.", 0);
+		save_webpasses();
+		file_close(fp);
+		return;
+	}
+
+	for (;;)
+	{
+		word = fread_word(fp);
+
+		if (!str_cmp(word, "#!"))
+			break;
+
+		if (str_cmp(word, "#WPWD"))
+		{
+			bugf("word doesn't exist (%s)", word);
+			exit(1);
+		}
+
+		ppwd = new_pwd();
+		load_struct(fp, &pwd, pwdsavetable, ppwd);
+		LINK(ppwd, wpwd_first, wpwd_last, next, prev);
+	}
 	file_close(fp);
 }
diff -ur src/telnet.c new/telnet.c
--- src/telnet.c	Fri Feb 21 23:16:37 2003
+++ new/telnet.c	Fri Feb 21 23:28:00 2003
@@ -34,8 +34,6 @@
 #include "merc.h"
 #include "telnet.h"
 
-bool write_to_descriptor args((DESCRIPTOR_DATA * d, char *txt, int length));
-
 char echo_off_str[] = { IAC, WILL, TELOPT_ECHO, '\0' };
 char echo_on_str[] = { IAC, WONT, TELOPT_ECHO, '\0' };
 char echo_dont[] = { IAC, DONT, TELOPT_ECHO, '\0' };
diff -ur src/webserver.c new/webserver.c
--- src/webserver.c	Fri Feb 21 23:16:37 2003
+++ new/webserver.c	Fri Feb 21 23:31:47 2003
@@ -84,6 +84,147 @@
 #include "recycle.h"
 #include "magic.h"
 #include "gsn.h"
+#include "telnet.h"
+
+void update_webpasses(CHAR_DATA * ch, bool pDelete)
+{
+	WPWD_DATA *c_next;
+	WPWD_DATA *curr;
+
+	if (IS_NPC(ch))
+		return;
+
+	for (curr = wpwd_first; curr != NULL; curr = c_next)
+	{
+		c_next = curr->next;
+
+		if (!str_cmp(ch->name, curr->name))
+		{
+			UNLINK(curr, wpwd_first, wpwd_last, next, prev);
+			free_pwd(curr);
+			save_webpasses();
+		}
+	}
+	if (pDelete || IS_NULLSTR(ch->pcdata->webpass))
+		return;
+
+	curr = new_pwd();
+	replace_string(curr->name, ch->name);
+	replace_string(curr->passw, ch->pcdata->webpass);
+	LINK(curr, wpwd_first, wpwd_last, next, prev);
+	save_webpasses();
+	return;
+}
+
+CH_CMD(do_webpass)
+{
+	char arg1[MIL];
+	char arg2[MIL];
+	char *pArg;
+	char *pwdnew;
+	char *p;
+	char cEnd;
+
+	if (!ch || IS_NPC(ch))
+		return;
+
+	if (!IS_IMMORTAL(ch))
+	{
+		chprintln(ch, "This feature is only available to immortals, sorry.");
+		return;
+	}
+
+	pArg = arg1;
+	while (isspace(*argument))
+		argument++;
+
+	cEnd = ' ';
+	if (*argument == '\'' || *argument == '\"')
+		cEnd = *argument++;
+
+	while (*argument != '\0')
+	{
+		if (*argument == cEnd)
+		{
+			argument++;
+			break;
+		}
+		*pArg++ = *argument++;
+	}
+	*pArg = '\0';
+
+	pArg = arg2;
+	while (isspace(*argument))
+		argument++;
+
+	cEnd = ' ';
+	if (*argument == '\'' || *argument == '\"')
+		cEnd = *argument++;
+
+	while (*argument != '\0')
+	{
+		if (*argument == cEnd)
+		{
+			argument++;
+			break;
+		}
+		*pArg++ = *argument++;
+	}
+	*pArg = '\0';
+
+	if (IS_NULLSTR(arg1) || IS_NULLSTR(arg2))
+	{
+		chprintln(ch, "Syntax: webpass <old> <new>.");
+		return;
+	}
+
+	write_to_descriptor(ch->desc, echo_off_str, 0);
+
+	if (str_cmp(crypt(arg1, ch->pcdata->webpass), ch->pcdata->webpass))
+	{
+		WAIT_STATE(ch, 40);
+		chprintln(ch, "Wrong password.  Wait 10 seconds.");
+		write_to_descriptor(ch->desc, echo_on_str, 0);
+		return;
+	}
+
+	if (strlen(arg2) < 5)
+	{
+		chprintln(ch, "New password must be at least five characters long.");
+		write_to_descriptor(ch->desc, echo_on_str, 0);
+		return;
+	}
+
+	pwdnew = crypt(arg2, ch->name);
+	for (p = pwdnew; *p != '\0'; p++)
+	{
+		if (*p == '~')
+		{
+			chprintln(ch, "New password not acceptable, try again.");
+			write_to_descriptor(ch->desc, echo_on_str, 0);
+			return;
+		}
+	}
+
+	replace_string(ch->pcdata->webpass, pwdnew);
+	save_char_obj(ch);
+	update_webpasses(ch, FALSE);
+	chprintln(ch, "Ok.");
+	write_to_descriptor(ch->desc, echo_on_str, 0);
+	return;
+}
+
+bool check_web_pass(const char *username, const char *password)
+{
+	WPWD_DATA *current;
+
+    for (current = wpwd_first; current; current = current->next)
+		if (!strcasecmp(current->name, username))
+			if (!strcasecmp(current->passw, crypt(password, username)))
+				return TRUE;
+
+	return FALSE;
+}
 
 /* Thanks to John Ludeman for this code...
  * Define translation matrix for Base64 decode.
@@ -2042,8 +2183,7 @@
 				}
 			}
 
-			if (!strcasecmp(username, SECURE_USERNAME)
-				&& !strcasecmp(password, SECURE_PASSWORD))
+			if (check_web_pass(username, password))
 			{
 				char *buf;
 
diff -ur src/webserver.h new/webserver.h
--- src/webserver.h	Fri Feb 21 23:16:37 2003
+++ new/webserver.h	Fri Feb 21 23:28:00 2003
@@ -44,8 +44,6 @@
  */
 
 #define SECURE_URL      "staffarea"	/* The secure URL. http://mud.is.here:<port>/SECURE_URL */
-#define SECURE_USERNAME "1stmud"	/* secure url username */
-#define SECURE_PASSWORD "2003"	/* secure url password */
 
 #define AUTH_DOMAIN     "Staff Area - Username and Password are CASE SENSITIVE."	/* Secure Area Description (tell me where this is used) */
 #define MAXDATA         1024