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	Sat Mar 15 18:39:12 2003
+++ new/act_comm.c	Thu Mar 20 15:08:45 2003
@@ -55,6 +55,9 @@
 CH_CMD(do_delete)
 {
 	char strsave[MAX_INPUT_LENGTH];
+	int hash;
+	ROOM_INDEX_DATA *pRoom;
+	void update_webpasses(CHAR_DATA * ch, bool pDelete);
 
 	if (IS_NPC(ch))
 		return;
@@ -71,6 +74,23 @@
 		{
 			delete_home(ch);
 			update_statlist(ch, TRUE);
+			update_webpasses(ch, TRUE);
+			if (is_clan(ch))
+			{
+				update_members(ch, TRUE);
+			}
+			for (hash = 0; hash < MAX_KEY_HASH; hash++)
+			{
+				for (pRoom = room_index_hash[hash]; pRoom != NULL;
+					 pRoom = pRoom->next)
+				{
+					if (!IS_NULLSTR(pRoom->owner)
+						&& !str_cmp(pRoom->owner, ch->name))
+					{
+						replace_string(pRoom->owner, "");
+					}
+				}
+			}
 			sprintf(strsave, "%s%s", PLAYER_DIR, capitalize(ch->name));
 			wiznet("$N turns $Mself into line noise.", ch, NULL, 0, 0, 0);
 			stop_fighting(ch, TRUE);
@@ -93,6 +113,66 @@
 	wiznet("$N is contemplating deletion.", ch, NULL, 0, 0, get_trust(ch));
 }
 
+void update_last_data(CHAR_DATA * sender, CHAR_DATA * viewer, int last,
+					  const char *chan, const char *str, int type)
+{
+	int i;
+	char time[MIL];
+	char buf[MSL];
+
+	if (IS_NPC(viewer) || IS_NULLSTR(str) || IS_NULLSTR(chan) || last < 0
+		|| last >= LAST_MAX)
+		return;
+
+	for (i = LAST_PAGE_LENGTH - 1; i > 0; i--)
+	{
+		replace_string(viewer->pcdata->history[last][i],
+					   viewer->pcdata->history[last][i - 1]);
+	}
+
+	strftime(time, 100, "%r", localtime(&current_time));
+	switch (type)
+	{
+	case CHANNEL_NORMAL:
+		sprintf(buf, "[%s] %s{x %s says '%s'{x", time, chan, PERS(sender,
+																  viewer), str);
+		replace_string(viewer->pcdata->history[last][0], buf);
+		break;
+	case CHANNEL_SOCIAL:
+		sprintf(buf, "[%s] %s{x %s{x", time, chan, str);
+		replace_string(viewer->pcdata->history[last][0], buf);
+		break;
+	case CHANNEL_EMOTE:
+		sprintf(buf, "[%s] %s{x %s %s{x",
+				time, chan, PERS(sender, viewer), str);
+		replace_string(viewer->pcdata->history[last][0], buf);
+		break;
+	default:
+		bugf("bad channel type [%d]", type);
+		break;
+	}
+}
+
+void view_last_data(CHAR_DATA * ch, int last)
+{
+	int i;
+	bool found = FALSE;
+
+	if (last < 0 || last >= LAST_MAX)
+		return;
+
+	for (i = LAST_PAGE_LENGTH - 1; i >= 0; i--)
+	{
+		if (!IS_NULLSTR(ch->pcdata->history[last][i]))
+		{
+			found = TRUE;
+			chprintln(ch, ch->pcdata->history[last][i]);
+		}
+	}
+	if (!found)
+		chprintln(ch, "None.");
+}
+
 bool display_channel(CHAR_DATA * ch, CHAR_DATA * victim,
 					 enum special_flags spec_flag)
 {
@@ -127,7 +207,7 @@
 
 void channel_social(CHAR_DATA * ch, CHAR_DATA * victim,
 					flag_t bit, const char *string, const char *type,
-					enum special_flags spec_flag)
+					enum special_flags spec_flag, int last_type)
 {
 	DESCRIPTOR_DATA *d;
 
@@ -146,13 +226,20 @@
 			char buf[MSL];
 
 			sprintf(buf, "%s %s", type, string);
-			perform_act(buf, ch, NULL, victim, FALSE, vch);
+			perform_act(buf, ch, NULL, victim, 0, vch);
+			update_last_data(ch, vch, last_type, type,
+							 perform_act_string(string, ch, NULL, victim,
+												FALSE), CHANNEL_SOCIAL);
 		}
 	}
+	update_last_data(ch, ch, last_type, type,
+					 perform_act_string(string, ch, NULL, victim, FALSE),
+					 CHANNEL_SOCIAL);
 }
 
 void public_ch(CHAR_DATA * ch, const char *argument,
-			   const char *type, flag_t bitname, enum special_flags spec_flag)
+			   const char *type, flag_t bitname, enum special_flags spec_flag,
+			   int last_type)
 {
 	char command[MIL + 100];
 	DESCRIPTOR_DATA *d;
@@ -239,7 +326,7 @@
 				act_new(buf, ch, NULL, NULL, TO_CHAR, POS_DEAD);
 				channel_social(ch, NULL, bitname,
 							   social_table[cmd].others_no_arg, type,
-							   spec_flag);
+							   spec_flag, last_type);
 			}
 			else if ((victim = get_char_world(ch, argx)) == NULL)
 			{
@@ -259,7 +346,7 @@
 					act_new(buf, ch, NULL, NULL, TO_CHAR, POS_DEAD);
 					channel_social(ch, victim, bitname,
 								   social_table[cmd].others_auto, type,
-								   spec_flag);
+								   spec_flag, last_type);
 				}
 				else
 				{
@@ -275,7 +362,7 @@
 					}
 					channel_social(ch, victim, bitname,
 								   social_table[cmd].others_found, type,
-								   spec_flag);
+								   spec_flag, last_type);
 				}
 			}
 			return;
@@ -286,6 +373,7 @@
 
 			chprintlnf(ch, "%s %s %s{x", type,
 					   IS_NPC(ch) ? ch->short_descr : ch->name, argument);
+			update_last_data(ch, ch, last_type, type, argument, CHANNEL_EMOTE);
 		}
 		else if (!str_cmp(command, "wholist"))
 		{
@@ -293,9 +381,19 @@
 			chprintlnf(ch, "{WPlayers on %s{x", type);
 			chprintln(ch, "{C-------------------{x");
 		}
+		else if (!str_cmp(command, "-h") && !IS_NPC(ch) && last_type >= 0
+				 && last_type < LAST_MAX)
+		{
+			chprintlnf(ch, "{WLast %d messages on %s{x", LAST_PAGE_LENGTH,
+					   type);
+			chprintln(ch, "{C------------------------------{x");
+			view_last_data(ch, last_type);
+			return;
+		}
 		else
 		{
 			chprintlnf(ch, "%s You say '%s'{x", type, arg_left);
+			update_last_data(ch, ch, last_type, type, arg_left, CHANNEL_NORMAL);
 		}
 		for (d = descriptor_first; d != NULL; d = d->next)
 		{
@@ -317,11 +415,15 @@
 				{
 					chprintlnf(victim, "%s %s %s{x", type,
 							   smash_colour(PERS(ch, victim)), argument);
+					update_last_data(ch, victim, last_type, type, argument,
+									 CHANNEL_EMOTE);
 				}
 				else
 				{
 					chprintlnf(victim, "%s %s says '%s'{x", type,
 							   smash_colour(PERS(ch, victim)), arg_left);
+					update_last_data(ch, victim, last_type, type, arg_left,
+									 CHANNEL_NORMAL);
 				}
 			}
 			else
@@ -541,38 +643,39 @@
 CH_CMD(do_gossip)
 {
 	public_ch(ch, argument, CTAG(_GOSSIP1) "[Gossip]" CTAG(_GOSSIP2),
-			  COMM_NOGOSSIP, spec_public_flag);
+			  COMM_NOGOSSIP, spec_public_flag, LAST_GOSSIP);
 }
 
 CH_CMD(do_ooc)
 {
-	public_ch(ch, argument, "{C({WOOC{C){w", COMM_NOOOC, spec_public_flag);
+	public_ch(ch, argument, "{C({WOOC{C){w", COMM_NOOOC, spec_public_flag,
+			  LAST_OOC);
 }
 
 CH_CMD(do_grats)
 {
 	public_ch(ch, argument, CTAG(_GRATS1) "[Grats]" CTAG(_GRATS2), COMM_NOGRATS,
-			  spec_public_flag);
+			  spec_public_flag, LAST_GRATS);
 }
 
 CH_CMD(do_quote)
 {
 	public_ch(ch, argument, CTAG(_QUOTE1) "[Quote]" CTAG(_QUOTE2), COMM_NOQUOTE,
-			  spec_public_flag);
+			  spec_public_flag, LAST_QUOTE);
 }
 
 /* RT question channel */
 CH_CMD(do_question)
 {
 	public_ch(ch, argument, CTAG(_QA1) "[Question]" CTAG(_QA2), COMM_NOQUESTION,
-			  spec_public_flag);
+			  spec_public_flag, LAST_QA);
 }
 
 /* RT answer channel - uses same line as questions */
 CH_CMD(do_answer)
 {
 	public_ch(ch, argument, CTAG(_QA1) "[Answer]" CTAG(_QA2), COMM_NOQUESTION,
-			  spec_public_flag);
+			  spec_public_flag, LAST_QA);
 }
 
 /* RT music channel */
@@ -580,7 +683,7 @@
 {
 	public_ch(ch, argument,
 			  CTAG(_MUSIC1) "[" CTAG(_MUSIC2) "MUSIC" CTAG(_MUSIC1) "]"
-			  CTAG(_MUSIC3), COMM_NOMUSIC, spec_public_flag);
+			  CTAG(_MUSIC3), COMM_NOMUSIC, spec_public_flag, LAST_MUSIC);
 }
 
 /* clan channels */
@@ -592,14 +695,15 @@
 		return;
 	}
 
-	public_ch(ch, argument, "{r[{RClan{r]{Y", COMM_NOCLAN, spec_clan_flag);
+	public_ch(ch, argument, "{r[{RClan{r]{Y", COMM_NOCLAN, spec_clan_flag,
+			  LAST_CLANTALK);
 }
 
 CH_CMD(do_immtalk)
 {
 	public_ch(ch, argument,
 			  CTAG(_IMMTALK1) "[" CTAG(_IMMTALK2) "ImmTalk" CTAG(_IMMTALK1) "]"
-			  CTAG(_IMMTALK3), COMM_NOWIZ, spec_imm_flag);
+			  CTAG(_IMMTALK3), COMM_NOWIZ, spec_imm_flag, LAST_IMMTALK);
 }
 
 CH_CMD(do_say)
@@ -1107,6 +1211,8 @@
 
 	save_char_obj(ch);
 	update_statlist(ch, FALSE);
+	if (is_clan(ch))
+		update_members(ch, FALSE);
 	chprintln(ch, "Saving. Remember that ROM has automatic saving now.");
 	WAIT_STATE(ch, PULSE_VIOLENCE);
 	return;
diff -ur src/act_wiz.c new/act_wiz.c
--- src/act_wiz.c	Sat Mar 15 18:39:12 2003
+++ new/act_wiz.c	Thu Mar 20 15:08:45 2003
@@ -205,6 +205,7 @@
 		chprintln(victim, "You are now a member of no clan!");
 		victim->clan = -1;
 		victim->rank = 0;
+		update_members(victim, TRUE);
 		return;
 	}
 
@@ -227,8 +228,14 @@
 				   capitalize(clan_table[clan].name));
 	}
 
+	if (is_clan(victim))
+	{
+		update_members(victim, TRUE);
+	}
+
 	victim->clan = clan;
 	victim->rank = 0;
+	update_members(victim, FALSE);
 }
 
 /* equips a character */
@@ -1478,8 +1485,9 @@
 	chprintlnf(ch,
 			   "Vnum: %ld  Format: %s  Race: %s  Group: %d  Sex: %s  Room: %ld",
 			   IS_NPC(victim) ? victim->pIndexData->vnum : 0,
-			   IS_NPC(victim) ? victim->pIndexData->
-			   new_format ? "new" : "old" : "pc", race_table[victim->race].name,
+			   IS_NPC(victim) ? victim->
+			   pIndexData->new_format ? "new" : "old" : "pc",
+			   race_table[victim->race].name,
 			   IS_NPC(victim) ? victim->group : 0, sex_table[victim->sex].name,
 			   victim->in_room == NULL ? 0 : victim->in_room->vnum);
 
@@ -4086,8 +4094,8 @@
 			count++;
 			sprintf(buf + strlen(buf), "[%3d %2d] %s@%s\n\r",
 					d->descriptor, d->connected,
-					d->original ? d->original->name : d->character ? d->
-					character->name : "(none)", d->host);
+					d->original ? d->original->name : d->
+					character ? d->character->name : "(none)", d->host);
 		}
 	}
 	if (count == 0)
diff -ur src/buddy.c new/buddy.c
--- src/buddy.c	Sat Mar 15 18:39:12 2003
+++ new/buddy.c	Thu Mar 20 15:08:45 2003
@@ -39,7 +39,7 @@
 
 	public_ch(ch, argument,
 			  "{W{{" CTAG(_BTALK1) "Buddy{W}" CTAG(_BTALK2), COMM_NOBUDDY,
-			  spec_buddy_flag);
+			  spec_buddy_flag, LAST_BTALK);
 	return;
 }
 
diff -ur src/clans.c new/clans.c
--- src/clans.c	Sat Mar 15 18:39:12 2003
+++ new/clans.c	Thu Mar 20 15:08:45 2003
@@ -37,6 +37,7 @@
 #include "interp.h"
 #include "lookup.h"
 #include "tables.h"
+#include "recycle.h"
 
 bool is_leader(CHAR_DATA * ch)
 {
@@ -105,6 +106,7 @@
 		chprintlnf(victim, "You have been demoted to %s, by %s.",
 				   clan_table[victim->clan].rank[rank].rankname, ch->name);
 		victim->rank = rank;
+		update_members(victim, FALSE);
 	}
 	else
 	{
@@ -115,18 +117,37 @@
 				   clan_table[victim->clan].rank[rank].rankname,
 				   capitalize(clan_table[victim->clan].name));
 		victim->rank = rank;
+		update_members(victim, FALSE);
 	}
 }
 
 CH_CMD(do_clist)
 {
 	int i;
+	MBR_DATA *pmbr;
+	char buf[MSL];
+	char buf2[MSL];
 
 	chprintln(ch, "Clans available:");
 	chprintln(ch, draw_line(NULL, 0));
 	for (i = 0; i < maxClan; i++)
 	{
-		chprintln(ch, clan_table[i].who_name);
+		chprint(ch, clan_table[i].who_name);
+		buf[0] = '\0';
+		buf2[0] = '\0';
+		for (pmbr = mbr_first; pmbr != NULL; pmbr = pmbr->next)
+		{
+			if (pmbr->clan != i || pmbr->rank != (MAX_RANK - 1))
+				continue;
+			sprintf(buf2, " %s,", pmbr->name);
+			strcat(buf, buf2);
+		}
+		if (!IS_NULLSTR(buf))
+		{
+			buf[strlen(buf) - 1] = '\0';
+			chprintf(ch, " (Leaders:%s)", buf);
+		}
+		chprintln(ch, "{x");
 	}
 	chprintln(ch, draw_line(NULL, 0));
 	chprintln(ch, "For more info use 'cinfo <clan>'.");
@@ -270,6 +291,8 @@
 				  "      : clanadmin invite <char>                        - invite a character to your clan.");
 		chprintln(ch,
 				  "      : clanadmin outcast <char>                       - kick a person out of your clan.");
+		chprintln(ch,
+				  "      : clanadmin members                              - list members in clan.");
 		if (IS_IMMORTAL(ch))
 			chprintln
 				(ch,
@@ -323,6 +346,26 @@
 		do_function(ch, &do_promote, argument);
 		return;
 	}
+	else if (!str_prefix(arg1, "members"))
+	{
+		MBR_DATA *mbr;
+		bool found = FALSE;
+
+		chprintln(ch, "Lev  Name         Rank");
+		chprintln(ch, "--- ------------ ------------");
+		for (mbr = mbr_first; mbr != NULL; mbr = mbr->next)
+		{
+			if (mbr->clan != clan)
+				continue;
+
+			chprintlnf(ch, "%3d %12s %12s", mbr->level, mbr->name,
+					   clan_table[mbr->clan].rank[mbr->rank].rankname);
+			found = TRUE;
+		}
+		if (!found)
+			chprintln(ch, "No one in the clan.");
+		return;
+	}
 	else if (!str_prefix(arg1, "invite"))
 	{
 		if ((victim = get_char_world(ch, argument)) == NULL)
@@ -389,6 +432,7 @@
 		}
 		chprintln(ch, "They are now clanless.");
 		chprintln(victim, "Your clan leader has kicked you out!");
+		update_members(victim, TRUE);
 		victim->clan = -1;
 		victim->rank = 0;
 		char_from_room(victim);
@@ -438,6 +482,7 @@
 				   clan_table[ch->clan].rank[ch->rank].rankname,
 				   clan_table[ch->clan].who_name);
 		ch->invited = -1;
+		update_members(ch, FALSE);
 		return;
 	}
 	else if (!str_cmp(arg1, "deny"))
@@ -458,4 +503,129 @@
 		chprintln(ch, "Syntax: join <accept|deny>");
 		return;
 	}
+}
+
+void update_members(CHAR_DATA * ch, bool pdelete)
+{
+	MBR_DATA *curr, *next;
+
+	if (IS_NPC(ch))
+		return;
+
+	for (curr = mbr_first; curr != NULL; curr = next)
+	{
+		next = curr->next;
+
+		if (!str_cmp(ch->name, curr->name))
+		{
+			UNLINK(curr, mbr_first, mbr_last, next, prev);
+
+			free_mbr(curr);
+			save_members();
+		}
+	}
+	if (pdelete || !is_clan(ch) || clan_table[ch->clan].independent)
+		return;
+
+	curr = new_mbr();
+	replace_string(curr->name, ch->name);
+	curr->rank = ch->rank;
+	curr->clan = ch->clan;
+	curr->level = ch->level;
+	LINK(curr, mbr_first, mbr_last, next, prev);
+	save_members();
+	return;
+}
+
+CH_CMD(do_roster)
+{
+	int i, clan, count = 0;
+	MBR_DATA *pmbr;
+	char buf[MSL], buf2[MSL];
+	char arg[MIL];
+	char *rcol[MAX_RANK] = { "{R", "{B", "{Y", "{M", "{G", "{C" };
+
+	argument = one_argument(argument, arg);
+
+	if (IS_NULLSTR(arg))
+	{
+		chprintln(ch, "Syntax: roster <clan name>");
+		if (IS_IMMORTAL(ch))
+			chprintln(ch, "        roster delete <name>");
+		return;
+	}
+
+	if (!str_cmp(arg, "delete") && IS_IMMORTAL(ch))
+	{
+		MBR_DATA *next = NULL;
+		MBR_DATA *curr = NULL;
+		bool found = FALSE;
+
+		for (curr = mbr_first; curr != NULL; curr = next)
+		{
+			next = curr->next;
+
+			if (!str_cmp(argument, curr->name))
+			{
+				UNLINK(curr, mbr_first, mbr_last, next, prev);
+
+				free_mbr(curr);
+				save_members();
+				found = TRUE;
+			}
+		}
+		if (!found)
+			chprintlnf(ch, "Error deleting %s.", argument);
+		else
+			chprintlnf(ch, "%s removed from member list.", argument);
+		return;
+	}
+
+	if ((clan = clan_lookup(arg)) == -1)
+	{
+		chprintln(ch, "That clan does not exist.");
+		return;
+	}
+
+	if (clan_table[clan].independent)
+	{
+		chprintln(ch, "That is not a real clan.");
+		return;
+	}
+
+	chprintlnf(ch, "{W%s{x\n\r",
+			   stringf(0, ALIGN_CENTER, "-", FORMATF("[ %s{W Roster ]",
+													 clan_table
+													 [clan].who_name)));
+	for (i = MAX_RANK - 1; i >= 0; i--)
+	{
+		chprintf(ch, "%s%12ss {W:%s", rcol[i],
+				 clan_table[clan].rank[i].rankname, rcol[i]);
+		buf[0] = '\0';
+		buf2[0] = '\0';
+		count = 0;
+		for (pmbr = mbr_first; pmbr != NULL; pmbr = pmbr->next)
+		{
+			if (pmbr->rank != i || pmbr->clan != clan || IS_NULLSTR(pmbr->name))
+				continue;
+			sprintf(buf2, " %s%12s {W({wLvl:{R%3d{W) ", rcol[i],
+					pmbr->name, pmbr->level);
+			strcat(buf, buf2);
+			if (++count % 2 == 0)
+			{
+				sprintf(buf2, "\n\r%15s", " ");
+				strcat(buf, buf2);
+			}
+		}
+		if (IS_NULLSTR(buf))
+			chprintlnf(ch, "  %12s\n\r", "No one.");
+		else
+		{
+			sprintf(buf2, "\n\r%s", count % 2 != 0 ? "\n\r" : "");
+			strcat(buf, buf2);
+			chprint(ch, buf);
+		}
+	}
+	chprintlnf(ch, "{W%s", draw_line(NULL, 0));
+	return;
 }
diff -ur src/comm.c new/comm.c
--- src/comm.c	Sat Mar 15 18:39:12 2003
+++ new/comm.c	Thu Mar 20 15:08:45 2003
@@ -1577,8 +1577,8 @@
 						((!IS_NPC(ch) &&
 						  IS_SET(ch->act, PLR_HOLYLIGHT)) ||
 						 (!IS_AFFECTED(ch, AFF_BLIND) &&
-						  !room_is_dark(ch->in_room))) ? ch->in_room->
-						name : "darkness");
+						  !room_is_dark(ch->in_room))) ? ch->
+						in_room->name : "darkness");
 			else
 				sprintf(buf2, " ");
 			i = buf2;
@@ -1879,8 +1879,8 @@
 			dold->connected != CON_GET_NAME &&
 			dold->connected != CON_GET_OLD_PASSWORD &&
 			!str_cmp(name,
-					 dold->original ? dold->original->name : dold->character->
-					 name))
+					 dold->original ? dold->original->name : dold->
+					 character->name))
 		{
 			write_to_buffer(d, "That character is already playing.\n\r", 0);
 			write_to_buffer(d, "Do you wish to connect anyway (Y/N)?", 0);
@@ -2290,6 +2290,197 @@
 	}
 
 	return;
+}
+
+const char *perform_act_string(const char *orig, CHAR_DATA * ch,
+							   const void *arg1, const void *arg2, bool cReturn)
+{
+	static char *const he_she[] = { "it", "he", "she" };
+	static char *const him_her[] = { "it", "him", "her" };
+	static char *const his_her[] = { "its", "his", "her" };
+	CHAR_DATA *vch = (CHAR_DATA *) arg2;
+	OBJ_DATA *obj1 = (OBJ_DATA *) arg1;
+	OBJ_DATA *obj2 = (OBJ_DATA *) arg2;
+	const char *str, *i = NULL;
+	char *point;
+	static char buf[MSL];
+
+	point = buf;
+	str = orig;
+
+	while (*str != '\0')
+	{
+		if (*str != '$')
+		{
+			*point++ = *str++;
+			continue;
+		}
+
+		++str;
+		i = "<@@@>";
+		if (!arg2 && *str >= 'A' && *str <= 'Z')
+		{
+			logf("perform_act:missing arg2 for code %d.", *str);
+			i = " <@@@> ";
+		}
+		else
+		{
+			switch (*str)
+			{
+			default:
+				logf("perform_act:bad code %c.", *str);
+				i = " <@@@> ";
+				break;
+
+			case '$':
+				i = "$";
+				break;
+			case 't':
+				if (arg1)
+				{
+					i = (const char *) arg1;
+				}
+				else
+					log_string("perform_act:bad code $t for 'arg1'");
+				break;
+			case 'T':
+				if (arg2)
+					i = (const char *) arg2;
+				else
+					log_string("perform_act:bad code $T for 'arg2'");
+				break;
+			case 'n':
+				if (ch)
+					i = IS_NPC(ch) ? ch->short_descr : ch->name;
+				else
+					log_string("perform_act:bad code $n for 'ch'");
+				break;
+			case 'N':
+				if (vch)
+					i = IS_NPC(vch) ? vch->short_descr : vch->name;
+				else
+					log_string("perform_act:bad code $N for 'vch'");
+				break;
+			case 'e':
+				if (ch)
+					i = he_she[URANGE(0, ch->sex, 2)];
+				else
+					log_string("perform_act:bad code $e for 'ch'");
+				break;
+			case 'E':
+				if (vch)
+					i = he_she[URANGE(0, vch->sex, 2)];
+				else
+					log_string("perform_act:bad code $E for 'vch'");
+				break;
+			case 'm':
+				if (ch)
+					i = him_her[URANGE(0, ch->sex, 2)];
+				else
+					log_string("perform_act:bad code $m for 'ch'");
+				break;
+			case 'M':
+				if (vch)
+					i = him_her[URANGE(0, vch->sex, 2)];
+				else
+					log_string("perform_act:bad code $M for 'vch'");
+				break;
+			case 's':
+				if (ch)
+					i = his_her[URANGE(0, ch->sex, 2)];
+				else
+					log_string("perform_act:bad code $s for 'ch'");
+				break;
+			case 'S':
+				if (vch)
+					i = his_her[URANGE(0, vch->sex, 2)];
+				else
+					log_string("perform_act:bad code $S for 'vch'");
+				break;
+			case 'g':
+				if (ch && ch->deity != -1)
+					i = deity_table[ch->deity].name;
+				else
+					log_string("perform_act:bad code $g for 'ch'");
+				break;
+			case 'G':
+				if (vch && vch->deity != -1)
+					i = deity_table[vch->deity].name;
+				else
+					log_string("perform_act:bad code $G for 'vch'");
+				break;
+			case 'c':
+				if (ch && ch->clan != -1)
+					i = clan_table[ch->clan].name;
+				else
+					log_string("perform_act:bad code $c for 'ch'");
+				break;
+			case 'C':
+				if (vch && vch->clan != -1)
+					i = clan_table[vch->clan].name;
+				else
+					log_string("perform_act:bad code $C for 'vch'");
+				break;
+			case 'o':
+				if (obj1)
+					i = fname(obj1->name);
+				else
+					log_string("perform_act:bad code $o for 'to' and 'obj1'");
+				break;
+
+			case 'O':
+				if (obj2)
+					i = fname(obj2->name);
+				else
+					log_string("perform_act:bad code $O for 'obj2'");
+				break;
+
+			case 'p':
+				if (obj1)
+					i = obj1->short_descr;
+				else
+					log_string("perform_act:bad code $p for 'obj1'");
+				break;
+
+			case 'P':
+				if (obj2)
+					i = obj2->short_descr;
+				else
+					log_string("perform_act:bad code $P for 'obj2'");
+				break;
+
+			case 'd':
+				if (arg2 == NULL || ((const char *) arg2)[0] == '\0')
+				{
+					i = "door";
+				}
+				else
+				{
+					char name[MIL];
+
+					one_argument((const char *) arg2, name);
+					i = name;
+				}
+				break;
+			}
+		}
+
+		++str;
+		while ((*point = *i) != '\0')
+			++point, ++i;
+	}
+
+	*point++ = '{';
+	*point++ = 'x';
+	if (cReturn)
+	{
+		*point++ = '\n';
+		*point++ = '\r';
+	}
+	*point = '\0';
+	buf[0] = UPPER(buf[0]);
+
+	return buf;
 }
 
 #define SENDOK(ch, type)    ((IS_NPC(ch) || ((ch)->desc && (ch->desc->connected == CON_PLAYING))) \
diff -ur src/db.c new/db.c
--- src/db.c	Sat Mar 15 18:39:12 2003
+++ new/db.c	Thu Mar 20 15:08:45 2003
@@ -219,6 +219,9 @@
 
 	log_string("Loading races...");
 	load_races();
+	log_string("Loading clans...");
+	load_clans();
+	load_members();
 
 	/*
 	 * Read in all the area files.
@@ -334,8 +337,6 @@
 		log_string("Loading socials...");
 		load_social_table();
 		load_gquest_data();
-		log_string("Loading clans...");
-		load_clans();
 		log_string("Loading commands...");
 		load_commands();
 		load_corpses();
@@ -362,15 +363,16 @@
 {
 	AREA_DATA *pArea;
 
-	alloc_mem(pArea, AREA_DATA, 1);
+	pArea = new_area();
+	free_string(pArea->file_name);
 	pArea->file_name = fread_string(fp);
 
 	pArea->area_flags = AREA_LOADING;	/* OLC */
 	pArea->security = 9;		/* OLC *//* 9 -- Hugin */
-	pArea->builders = str_dup("None");	/* OLC */
 	pArea->vnum = top_area;		/* OLC */
-
+	free_string(pArea->name);
 	pArea->name = fread_string(fp);
+	free_string(pArea->credits);
 	pArea->credits = fread_string(fp);
 	pArea->min_vnum = fread_number(fp);
 	pArea->max_vnum = fread_number(fp);
@@ -428,13 +430,12 @@
 	const char *word;
 	bool fMatch;
 
-	alloc_mem(pArea, AREA_DATA, 1);
+	pArea = new_area();
 	pArea->age = 15;
 	pArea->nplayer = 0;
+	free_string(pArea->file_name);
 	pArea->file_name = str_dup(strArea);
 	pArea->vnum = top_area;
-	pArea->name = str_dup("New Area");
-	pArea->builders = str_dup("");
 	pArea->security = 9;		/* 9 -- Hugin */
 	pArea->min_vnum = 0;
 	pArea->max_vnum = 0;
@@ -521,7 +522,9 @@
 
 		pHelp = new_help();
 		pHelp->level = level;
+		free_string(pHelp->keyword);
 		pHelp->keyword = keyword;
+		free_string(pHelp->text);
 		pHelp->text = fread_string(fp);
 
 		if (!str_cmp(pHelp->keyword, "greeting"))
@@ -576,13 +579,17 @@
 		}
 		fBootDb = TRUE;
 
-		alloc_mem(pMobIndex, MOB_INDEX_DATA, 1);
+		pMobIndex = new_mob_index();
 		pMobIndex->vnum = vnum;
 		pMobIndex->area = current_area;	/* OLC */
 		pMobIndex->new_format = FALSE;
+		free_string(pMobIndex->player_name);
 		pMobIndex->player_name = fread_string(fp);
+		free_string(pMobIndex->short_descr);
 		pMobIndex->short_descr = fread_string(fp);
+		free_string(pMobIndex->long_descr);
 		pMobIndex->long_descr = fread_string(fp);
+		free_string(pMobIndex->description);
 		pMobIndex->description = fread_string(fp);
 
 /*
@@ -721,19 +728,21 @@
 		}
 		fBootDb = TRUE;
 
-		alloc_mem(pObjIndex, OBJ_INDEX_DATA, 1);
+		pObjIndex = new_obj_index();
 		pObjIndex->vnum = vnum;
 		pObjIndex->area = current_area;	/* OLC */
 		pObjIndex->new_format = FALSE;
 		pObjIndex->reset_num = 0;
+		free_string(pObjIndex->name);
 		pObjIndex->name = fread_string(fp);
+		free_string(pObjIndex->short_descr);
 		pObjIndex->short_descr = fread_string(fp);
+		free_string(pObjIndex->description);
 		pObjIndex->description = fread_string(fp);
 		/* Action description */ fread_string(fp);
 
 /*		pObjIndex->short_descr[0] = LOWER (pObjIndex->short_descr[0]);
 		pObjIndex->description[0] = UPPER (pObjIndex->description[0]); */
-		pObjIndex->material = str_dup("");
 
 		pObjIndex->item_type = fread_number(fp);
 		pObjIndex->extra_flags = fread_flag(fp);
@@ -767,7 +776,7 @@
 			{
 				AFFECT_DATA *paf;
 
-				alloc_mem(paf, AFFECT_DATA, 1);
+				paf = new_affect();
 				paf->where = TO_OBJECT;
 				paf->type = -1;
 				paf->level = 20;	/* RT temp fix */
@@ -784,8 +793,10 @@
 			{
 				EXTRA_DESCR_DATA *ed;
 
-				alloc_mem(ed, EXTRA_DESCR_DATA, 1);
+				ed = new_extra_descr();
+				free_string(ed->keyword);
 				ed->keyword = fread_string(fp);
+				free_string(ed->description);
 				ed->description = fread_string(fp);
 				LINK(ed, pObjIndex->first_extra_descr,
 					 pObjIndex->last_extra_descr, next, prev);
@@ -985,14 +996,16 @@
 		fBootDb = TRUE;
 
 		alloc_mem(pRoomIndex, ROOM_INDEX_DATA, 1);
-		pRoomIndex->owner = str_dup("");
+		pRoomIndex = new_room_index();
 		pRoomIndex->first_person = NULL;
 		pRoomIndex->clan = -1;
 		pRoomIndex->first_content = NULL;
 		pRoomIndex->first_extra_descr = NULL;
 		pRoomIndex->area = current_area;
 		pRoomIndex->vnum = vnum;
+		free_string(pRoomIndex->name);
 		pRoomIndex->name = fread_string(fp);
+		free_string(pRoomIndex->description);
 		pRoomIndex->description = fread_string(fp);
 		/* Area number */ fread_number(fp);
 		pRoomIndex->room_flags = fread_flag(fp);
@@ -1048,8 +1061,10 @@
 					exit(1);
 				}
 
-				alloc_mem(pexit, EXIT_DATA, 1);
+				pexit = new_exit();
+				free_string(pexit->description);
 				pexit->description = fread_string(fp);
+				free_string(pexit->keyword);
 				pexit->keyword = fread_string(fp);
 				pexit->exit_info = 0;
 				pexit->rs_flags = 0;	/* OLC */
@@ -1085,8 +1100,10 @@
 			{
 				EXTRA_DESCR_DATA *ed;
 
-				alloc_mem(ed, EXTRA_DESCR_DATA, 1);
+				ed = new_extra_descr();
+				free_string(ed->keyword);
 				ed->keyword = fread_string(fp);
+				free_string(ed->description);
 				ed->description = fread_string(fp);
 				LINK(ed, pRoomIndex->first_extra_descr,
 					 pRoomIndex->last_extra_descr, next, prev);
@@ -1110,7 +1127,7 @@
 				const char *word;
 				flag_t trigger = 0;
 
-				alloc_mem(pRprog, PROG_LIST, 1);
+				pRprog = new_prog();
 				word = fread_word(fp);
 				if (!(trigger = flag_value(rprog_flags, word)))
 				{
@@ -1120,6 +1137,7 @@
 				SET_BIT(pRoomIndex->rprog_flags, trigger);
 				pRprog->trig_type = trigger;
 				pRprog->vnum = fread_number(fp);
+				free_string(pRprog->trig_phrase);
 				pRprog->trig_phrase = fread_string(fp);
 				LINK(pRprog, pRoomIndex->first_rprog, pRoomIndex->last_rprog,
 					 next, prev);
@@ -1155,7 +1173,7 @@
 		MOB_INDEX_DATA *pMobIndex;
 		int iTrade;
 
-		alloc_mem(pShop, SHOP_DATA, 1);
+		pShop = new_shop();
 		pShop->keeper = fread_number(fp);
 		if (pShop->keeper == 0)
 			break;
@@ -1392,8 +1410,9 @@
 		}
 		fBootDb = TRUE;
 
-		alloc_mem(pMprog, PROG_CODE, 1);
+		pMprog = new_pcode();
 		pMprog->vnum = vnum;
+		free_string(pMprog->code);
 		pMprog->code = fread_string(fp);
 		LINK(pMprog, mprog_first, mprog_last, next, prev);
 		top_mprog_index++;
@@ -3163,6 +3182,27 @@
 		break;
 	case 3:
 		number += 1;
+		break;
+	}
+
+	return UMAX(1, number);
+}
+
+int number_fuzzier(int number)
+{
+	switch (number_range(0, 4))
+	{
+	case 0:
+		number -= 2;
+		break;
+	case 1:
+		number -= 1;
+		break;
+	case 3:
+		number += 1;
+		break;
+	case 4:
+		number += 2;
 		break;
 	}
 
diff -ur src/db2.c new/db2.c
--- src/db2.c	Sat Mar 15 18:39:12 2003
+++ new/db2.c	Thu Mar 20 15:08:45 2003
@@ -43,12 +43,15 @@
 #include "interp.h"
 #include "magic.h"
 #include "recycle.h"
+#include "olc.h"
 
 /* values for db2.c */
 
 extern AREA_DATA *current_area;
 int top_oprog_index;
 int top_rprog_index;
+int nAllocPerm;
+long sAllocPerm;
 
 /*
  * Snarf a mob section.  new style
@@ -68,6 +71,7 @@
 		vnum_t vnum;
 		char letter;
 		int iHash;
+		const char *tmp;
 
 		letter = fread_letter(fp);
 		if (letter != '#')
@@ -88,21 +92,22 @@
 		}
 		fBootDb = TRUE;
 
-		alloc_mem(pMobIndex, MOB_INDEX_DATA, 1);
+		pMobIndex = new_mob_index();
 		pMobIndex->vnum = vnum;
 		pMobIndex->area = current_area;	/* OLC */
 		pMobIndex->new_format = TRUE;
 		newmobs++;
+		free_string(pMobIndex->player_name);
 		pMobIndex->player_name = fread_string(fp);
+		free_string(pMobIndex->short_descr);
 		pMobIndex->short_descr = fread_string(fp);
+		free_string(pMobIndex->long_descr);
 		pMobIndex->long_descr = fread_string(fp);
+		free_string(pMobIndex->description);
 		pMobIndex->description = fread_string(fp);
-		pMobIndex->race = race_lookup(fread_string(fp));
-
-/*
-		pMobIndex->long_descr[0] = UPPER (pMobIndex->long_descr[0]);
-		pMobIndex->description[0] = UPPER (pMobIndex->description[0]);
-*/
+		tmp = fread_string(fp);
+		pMobIndex->race = race_lookup(tmp);
+		free_string(tmp);
 
 		pMobIndex->act =
 			fread_flag(fp) | ACT_IS_NPC | race_table[pMobIndex->race].act;
@@ -204,7 +209,7 @@
 				char *word;
 				int trigger = 0;
 
-				alloc_mem(pMprog, PROG_LIST, 1);
+				pMprog = new_prog();
 				word = fread_word(fp);
 				if ((trigger = flag_value(mprog_flags, word)) == 0)
 				{
@@ -214,6 +219,7 @@
 				SET_BIT(pMobIndex->mprog_flags, trigger);
 				pMprog->trig_type = trigger;
 				pMprog->vnum = fread_number(fp);
+				free_string(pMprog->trig_phrase);
 				pMprog->trig_phrase = fread_string(fp);
 				LINK(pMprog, pMobIndex->first_mprog, pMobIndex->last_mprog,
 					 next, prev);
@@ -274,15 +280,19 @@
 		}
 		fBootDb = TRUE;
 
-		alloc_mem(pObjIndex, OBJ_INDEX_DATA, 1);
+		pObjIndex = new_obj_index();
 		pObjIndex->vnum = vnum;
 		pObjIndex->area = current_area;	/* OLC */
 		pObjIndex->new_format = TRUE;
 		pObjIndex->reset_num = 0;
 		newobjs++;
+		free_string(pObjIndex->name);
 		pObjIndex->name = fread_string(fp);
+		free_string(pObjIndex->short_descr);
 		pObjIndex->short_descr = fread_string(fp);
+		free_string(pObjIndex->description);
 		pObjIndex->description = fread_string(fp);
+		free_string(pObjIndex->material);
 		pObjIndex->material = fread_string(fp);
 
 		CHECK_POS(pObjIndex->item_type, item_lookup(fread_word(fp)),
@@ -383,7 +393,7 @@
 			{
 				AFFECT_DATA *paf;
 
-				alloc_mem(paf, AFFECT_DATA, 1);
+				paf = new_affect();
 				paf->where = TO_OBJECT;
 				paf->type = -1;
 				paf->level = pObjIndex->level;
@@ -400,7 +410,7 @@
 			{
 				AFFECT_DATA *paf;
 
-				alloc_mem(paf, AFFECT_DATA, 1);
+				paf = new_affect();
 				pletter = fread_letter(fp);
 				switch (pletter)
 				{
@@ -435,8 +445,10 @@
 			{
 				EXTRA_DESCR_DATA *ed;
 
-				alloc_mem(ed, EXTRA_DESCR_DATA, 1);
+				ed = new_extra_descr();
+				free_string(ed->keyword);
 				ed->keyword = fread_string(fp);
+				free_string(ed->description);
 				ed->description = fread_string(fp);
 				LINK(ed, pObjIndex->first_extra_descr,
 					 pObjIndex->last_extra_descr, next, prev);
@@ -448,7 +460,7 @@
 				const char *word;
 				flag_t trigger = 0;
 
-				alloc_mem(pOprog, PROG_LIST, 1);
+				pOprog = new_prog();
 				word = fread_word(fp);
 				if (!(trigger = flag_value(oprog_flags, word)))
 				{
@@ -458,6 +470,7 @@
 				SET_BIT(pObjIndex->oprog_flags, trigger);
 				pOprog->trig_type = trigger;
 				pOprog->vnum = fread_number(fp);
+				free_string(pOprog->trig_phrase);
 				pOprog->trig_phrase = fread_string(fp);
 				LINK(pOprog, pObjIndex->first_oprog, pObjIndex->last_oprog,
 					 next, prev);
@@ -851,12 +864,19 @@
         IMP_COUNTER( type, prefix##free, f )
 
 // these object types have no global list
-IMP_COUNTER(PC_DATA, pcdata_free, f) IMP_COUNTER(AFFECT_DATA, affect_free, f)
+// *INDENT-OFF*
+
+IMP_COUNTER(PC_DATA, pcdata_free, f) 
+IMP_COUNTER(AFFECT_DATA, affect_free, f)
+
 // these do
 #define object_free obj_free
-	IMP_LIST_COUNTERS(OBJ_DATA, object_);
+IMP_LIST_COUNTERS(OBJ_DATA, object_);
 IMP_LIST_COUNTERS(CHAR_DATA, char_);
 IMP_LIST_COUNTERS(DESCRIPTOR_DATA, descriptor_);
+IMP_LIST_COUNTERS(MBR_DATA, mbr_);
+
+// *INDENT-ON*
 
 int nNOTE_DATA(void)
 {
@@ -910,6 +930,7 @@
 	rpt("Areas", top_area, AREA_DATA);
 	rpt("Resets", top_reset, RESET_DATA);
 	rpt("Help entries", top_help, HELP_DATA);
+	rpt_dy("Members", MBR_DATA);
 	rpt_dy("Notes", NOTE_DATA);
 	rpt("Socials", maxSocial, struct social_type);
 	chprint(ch, separator);
@@ -927,6 +948,7 @@
 	rptf("Descriptors", DESCRIPTOR_DATA);
 	rptf("Objects", OBJ_DATA);
 	rptf("Affects", AFFECT_DATA);
+	rptf("Members", MBR_DATA);
 	chprint(ch, separator);
 }
 
@@ -937,6 +959,8 @@
 	rptsd("String Space allocated at DB boot", MAX_STRING / 1024);
 	rptdsd(nAllocString, "Strings in string space", sAllocString / 1024);
 	rptsd("Excess string space", MAX_STRING / 1024 - sAllocString / 1024);
+	chprintlnf(ch, " Perms %d blocks of %ld kb.",
+			   nAllocPerm, sAllocPerm / 1024);
 
 	chprint(ch, separator);
 }
@@ -1210,8 +1234,9 @@
 		}
 		fBootDb = TRUE;
 
-		alloc_mem(pOprog, PROG_CODE, 1);
+		pOprog = new_pcode();
 		pOprog->vnum = vnum;
+		free_string(pOprog->code);
 		pOprog->code = fread_string(fp);
 		LINK(pOprog, oprog_first, oprog_last, next, prev);
 		top_oprog_index++;
@@ -1253,8 +1278,9 @@
 		}
 		fBootDb = TRUE;
 
-		alloc_mem(pRprog, PROG_CODE, 1);
+		pRprog = new_pcode();
 		pRprog->vnum = vnum;
+		free_string(pRprog->code);
 		pRprog->code = fread_string(fp);
 		LINK(pRprog, rprog_first, rprog_last, next, prev);
 		top_rprog_index++;
@@ -1424,4 +1450,42 @@
 		return 1;
 
 	return strcmp(cmd1.name, cmd2.name);
+}
+
+#define                 MAX_PERM_BLOCK  131072
+/*
+ * Allocate some permanent memory.
+ * Permanent memory is never freed,
+ *   pointers into it may be copied safely.
+ */
+void *alloc_perm(size_t sMem)
+{
+	static char *pMemPerm;
+	static int iMemPerm;
+	void *pMem;
+
+	while (sMem % sizeof(long) != 0)
+		sMem++;
+	if (sMem > MAX_PERM_BLOCK)
+	{
+		bugf("%d too large.", sMem);
+		exit(1);
+	}
+
+	if (pMemPerm == NULL || iMemPerm + sMem > MAX_PERM_BLOCK)
+	{
+		iMemPerm = 0;
+		if ((pMemPerm = (char *) calloc(1, MAX_PERM_BLOCK)) == NULL)
+		{
+			perror("Alloc_perm");
+			exit(1);
+		}
+	}
+
+	pMem = pMemPerm + iMemPerm;
+	iMemPerm += sMem;
+	nAllocPerm += 1;
+	sAllocPerm += sMem;
+
+	return pMem;
 }
diff -ur src/dofun.h new/dofun.h
--- src/dofun.h	Sat Mar 15 18:39:12 2003
+++ new/dofun.h	Thu Mar 20 15:08:46 2003
@@ -321,5 +321,7 @@
 COMMAND_FUN (do_punload)
 COMMAND_FUN (do_buddy)
 COMMAND_FUN (do_btalk)
+COMMAND_FUN (do_areaset)
+COMMAND_FUN (do_roster)
 
 // *INDENT-ON*
diff -ur src/globals.h new/globals.h
--- src/globals.h	Sat Mar 15 18:39:12 2003
+++ new/globals.h	Thu Mar 20 15:08:46 2003
@@ -117,11 +117,15 @@
 GLOBAL_DEF(DESCRIPTOR_DATA * descriptor_free, NULL);
 GLOBAL_DEF(OBJ_DATA * obj_free, NULL);
 GLOBAL_DEF(AFFECT_DATA * affect_free, NULL);
+GLOBAL_DEF(MBR_DATA * mbr_free, NULL);
 GLOBAL_DEF(int arena, FIGHT_OPEN);
 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);
+
+GLOBAL_DEF(MBR_DATA * mbr_first, NULL);
+GLOBAL_DEF(MBR_DATA * mbr_last, NULL);
 
 #endif
diff -ur src/merc.h new/merc.h
--- src/merc.h	Sat Mar 15 18:39:12 2003
+++ new/merc.h	Thu Mar 20 15:08:46 2003
@@ -147,6 +147,7 @@
 typedef struct clan_rank RANK_DATA;
 typedef struct deity_type DEITY_DATA;
 typedef struct wpwd_data WPWD_DATA;
+typedef struct mbr_data MBR_DATA;
 
 /*
  * Function types.
@@ -1561,6 +1562,17 @@
 	long gamestat[MAX_GAMESTAT];	// stat data
 };
 
+struct mbr_data
+{
+	MBR_DATA *next;
+	MBR_DATA *prev;
+	bool valid;
+	const char *name;
+	int rank;
+	int clan;
+	int level;
+};
+
 /*
  * One character (PC or NPC).
  */
@@ -1672,6 +1684,24 @@
 #define FIGHT_BUSY 2
 #define FIGHT_LOCK 3
 
+#define LAST_PAGE_LENGTH    20
+
+#define LAST_NONE        -1
+#define LAST_IMMTALK    0
+#define LAST_GOSSIP        1
+#define LAST_QA            2
+#define LAST_MUSIC        3
+#define LAST_CLANTALK    4
+#define LAST_QUOTE        5
+#define LAST_GRATS        6
+#define LAST_BTALK        7
+#define LAST_OOC          8
+#define LAST_MAX        9
+
+#define CHANNEL_NORMAL 0
+#define CHANNEL_SOCIAL 1
+#define CHANNEL_EMOTE  2
+
 /*
  * Data which only PC's have.
  */
@@ -1732,6 +1762,7 @@
 	const char *webpass;
 	char str_ed_key;
 	const char *buddies[MAX_BUDDY];
+	const char *history[LAST_MAX][LAST_PAGE_LENGTH];
 };
 
 /* Data for generating characters -- only used during generation */
@@ -2402,6 +2433,7 @@
 #define BANK_FILE       DATA_DIR "bank.dat"
 #define DEITY_FILE      DATA_DIR "deity.dat"
 #define WPWD_FILE       DATA_DIR "webpass.dat"
+#define MBR_FILE        DATA_DIR "mbr.dat"
 
 #include "proto.h"
 
diff -ur src/olc.c new/olc.c
--- src/olc.c	Sat Mar 15 18:39:12 2003
+++ new/olc.c	Thu Mar 20 15:08:46 2003
@@ -52,6 +52,7 @@
 #include "olc.h"
 #include "interp.h"
 #include "lookup.h"
+#include "recycle.h"
 
 MOB_INDEX_DATA xMob;
 OBJ_INDEX_DATA xObj;
@@ -488,6 +489,9 @@
 	 (const void *) position_flags},
 	{"defaultpos", (void *) &xMob.default_pos, olced_flag,
 	 (const void *) position_flags},
+	{"autoeasy", NULL, olced_olded, (const void *) medit_autoeasy},
+	{"autoset", NULL, olced_olded, (const void *) medit_autoset},
+	{"autohard", NULL, olced_olded, (const void *) medit_autohard},
 	{"damtype", (void *) &xMob.dam_type, olced_poslookup,
 	 (const void *) attack_lookup},
 	{"race", (void *) &xMob, olced_race, NULL},
@@ -513,6 +517,8 @@
 	{"addaffect", NULL, olced_olded, (const void *) oedit_addaffect},
 	{"addapply", NULL, olced_olded, (const void *) oedit_addapply},
 	{"delaffect", NULL, olced_olded, (const void *) oedit_delaffect},
+	{"autoweapon", NULL, olced_olded, (const void *) oedit_autoweapon},
+	{"autoarmor", NULL, olced_olded, (const void *) oedit_autoarmor},
 	{"v0", NULL, olced_value, (const void *) 0},
 	{"v1", NULL, olced_value, (const void *) 1},
 	{"v2", NULL, olced_value, (const void *) 2},
@@ -2815,4 +2821,351 @@
 		act("You are now entering the $t editor, type 'done' to finish.", ch,
 			olc_ed_name_long(ch), NULL, TO_CHAR);
 	}
+}
+
+void autoset(MOB_INDEX_DATA * pMob)
+{
+	double roll, size, bonus, avg;
+	double ac_n, ac_x;
+	int level;
+
+	if (!pMob || pMob->level < 1)
+		return;
+
+	level = pMob->level;
+
+	bonus = UMAX(1, (number_fuzzier(level) - 5));
+	ac_n =
+		80 - (level * (7.77 + (level / 90))) - ((level / 9) ^ 2) - (bonus * 2);
+	ac_x =
+		80 - (level * (6.67 + (level / 90))) - ((level / 9) ^ 2) - (bonus * 2);
+	pMob->ac[AC_PIERCE] = (int) ac_n;
+	pMob->ac[AC_BASH] = (int) ac_n;
+	pMob->ac[AC_SLASH] = (int) ac_n;
+	pMob->ac[AC_EXOTIC] = (int) ac_x;
+
+	pMob->mana[DICE_NUMBER] = number_fuzzier(level);
+	pMob->mana[DICE_TYPE] = number_fuzzier(10);
+	pMob->mana[DICE_BONUS] = number_fuzzier(85);
+
+	avg = (number_fuzzier(level) * .84);
+	roll = (number_fuzzier(level) / 9 + 1);
+	size = (number_fuzzier((int) roll) / 3);
+
+	for (size = roll / 3; roll * (size + 2) / 2 < avg; size++);
+
+	pMob->damage[DICE_NUMBER] = (int) UMAX(1, roll);
+	pMob->damage[DICE_TYPE] = (int) UMAX(2, size);
+	pMob->damage[DICE_BONUS] = (int) UMAX(1, number_fuzzier(level) * .89);
+
+	bonus =
+		UMAX(1,
+			 (level / 53 + 1) * ((level * 10) + (level / 10)) - UMIN(20,
+																	 (2 *
+																	  level))
+			 + 1);
+
+	size = number_fuzzier(level) * 1.2 - number_fuzzier(1);
+
+	roll = number_fuzzier(level) * 1.4 - number_fuzzier(2);
+
+	pMob->hit[DICE_NUMBER] = (int) UMAX(1, roll);
+	pMob->hit[DICE_TYPE] = (int) UMAX(2, size);
+	pMob->hit[DICE_BONUS] = (int) UMAX(10, bonus);
+
+	pMob->hitroll = number_range(level * 6 / 10, level);
+}
+
+void autohard(MOB_INDEX_DATA * pMob)
+{
+	double roll, size, bonus, avg;
+	double ac_n, ac_x;
+	int level;
+
+	if (!pMob || pMob->level < 1)
+		return;
+
+	level = pMob->level;
+
+	bonus = UMAX(1, (number_fuzzier(level) - 5));
+	ac_n =
+		70 - (level * (8.15 + (level / 90))) - ((level / 8) ^ 2) - (bonus * 2);
+	ac_x =
+		70 - (level * (7.12 + (level / 90))) - ((level / 8) ^ 2) - (bonus * 2);
+	pMob->ac[AC_PIERCE] = (int) ac_n;
+	pMob->ac[AC_BASH] = (int) ac_n;
+	pMob->ac[AC_SLASH] = (int) ac_n;
+	pMob->ac[AC_EXOTIC] = (int) ac_x;
+
+	pMob->mana[DICE_NUMBER] = number_fuzzier(level);
+	pMob->mana[DICE_TYPE] = number_fuzzier(12);
+	pMob->mana[DICE_BONUS] = number_fuzzier(95);
+
+	avg = (number_fuzzier(level) * .9);
+	roll = (number_fuzzier(level) / 9 + 1);
+	size = (number_fuzzier((int) roll) / 3);
+
+	for (size = roll / 3; roll * (size + 2) / 2 < avg; size++);
+
+	pMob->damage[DICE_NUMBER] = (int) UMAX(1, roll);
+	pMob->damage[DICE_TYPE] = (int) UMAX(2, size);
+	pMob->damage[DICE_BONUS] = (int) UMAX(1, number_fuzzier(level) * .99);
+
+	bonus = (level / 53 + 1) * ((level * 10) + (level / 10)) + 1;
+
+	size = number_fuzzier(level) * 1.2 - number_fuzzier(1);
+
+	size++;
+
+	roll = number_fuzzier(level) * 1.4 - number_fuzzier(2);
+
+	pMob->hit[DICE_NUMBER] = (int) UMAX(1, roll);
+	pMob->hit[DICE_TYPE] = (int) UMAX(2, size);
+	pMob->hit[DICE_BONUS] = (int) UMAX(10, bonus);
+
+	pMob->hitroll = number_range(level * 65 / 100, level);
+}
+
+void autoeasy(MOB_INDEX_DATA * pMob)
+{
+	double roll, size, bonus, avg;
+	double ac_n, ac_x;
+	int level;
+
+	if (!pMob || pMob->level < 1)
+		return;
+
+	level = pMob->level;
+
+	bonus = UMAX(1, (number_fuzzier(level) - 5));
+	ac_n =
+		90 - (level * (7.47 + (level / 90))) - ((level / 10) ^ 2) - (bonus * 2);
+	ac_x =
+		90 - (level * (6.37 + (level / 90))) - ((level / 10) ^ 2) - (bonus * 2);
+	pMob->ac[AC_PIERCE] = (int) ac_n;
+	pMob->ac[AC_BASH] = (int) ac_n;
+	pMob->ac[AC_SLASH] = (int) ac_n;
+	pMob->ac[AC_EXOTIC] = (int) ac_x;
+
+	pMob->mana[DICE_NUMBER] = number_fuzzier(level);
+	pMob->mana[DICE_TYPE] = number_fuzzier(10);
+	pMob->mana[DICE_BONUS] = number_fuzzier(60);
+
+	avg = (number_fuzzier(level) * .76);
+	roll = (number_fuzzier(level) / 9 + 1);
+	size = (number_fuzzier((int) roll) / 3);
+
+	for (size = roll / 3; roll * (size + 2) / 2 < avg; size++);
+
+	pMob->damage[DICE_NUMBER] = (int) UMAX(1, roll);
+	pMob->damage[DICE_TYPE] = (int) UMAX(2, size);
+	pMob->damage[DICE_BONUS] = (int) UMAX(1, number_fuzzier(level) * .82);
+
+	bonus =
+		UMAX(1,
+			 (level / 55 + 1) * ((level * 9) + (level / 10)) - UMIN(20,
+																	(1.5 *
+																	 level))
+			 + 1);
+
+	size = number_fuzzier(level) * 1.2 - number_fuzzier(1);
+
+	roll = number_fuzzier(level) * 1.4 - number_fuzzier(2);
+
+	pMob->hit[DICE_NUMBER] = (int) UMAX(1, roll);
+	pMob->hit[DICE_TYPE] = (int) UMAX(2, size);
+	pMob->hit[DICE_BONUS] = (int) UMAX(10, bonus);
+
+	pMob->hitroll = number_range(level * 59 / 100, level);
+}
+
+void autoweapon(OBJ_INDEX_DATA * pObj)
+{
+	AFFECT_DATA *pAf, *pObjAf;
+	bool bDamroll, bHitroll;
+	double pDice, size, bonus;
+	int level, mod;
+
+	if (!pObj || pObj->item_type != ITEM_WEAPON)
+		return;
+
+	if (pObj->level < 1 || IS_OBJ_STAT(pObj, ITEM_QUEST))
+		return;
+
+	level = pObj->level;
+
+	bonus = UMAX(1, number_fuzzier(level) / 9 - 1);
+	pDice = (number_fuzzier(level) * .22 + 2);
+	size = (number_fuzzier((int) pDice) / 2);
+
+	for (size = pDice / 2; pDice * (size + 2) / 2 < level; size++);
+
+	pDice = UMAX(2, pDice);
+	size = UMAX(3, size);
+
+	switch (pObj->value[0])
+	{
+	default:
+	case WEAPON_EXOTIC:
+	case WEAPON_SWORD:
+		break;
+	case WEAPON_DAGGER:
+		pDice = UMAX(2, pDice - 1);
+		size = UMAX(3, size - 1);
+		break;
+	case WEAPON_SPEAR:
+	case WEAPON_POLEARM:
+		size++;
+		break;
+	case WEAPON_MACE:
+	case WEAPON_AXE:
+		size = UMAX(3, size - 1);
+		break;
+	case WEAPON_FLAIL:
+	case WEAPON_WHIP:
+		pDice = UMAX(2, pDice - 1);
+		break;
+	}
+
+	pDice += 1;
+	size -= 1;
+
+	pDice = UMAX(2, number_fuzzier((int) pDice));
+	size = UMAX(3, number_fuzzier((int) size));
+
+	pObj->value[1] = (long) pDice;
+	pObj->value[2] = (long) size;
+
+	mod = UMAX(1, number_range(number_fuzzier((int) bonus) * 6 / 10,
+			number_fuzzier((int) bonus)));
+
+	if(mod > 0)
+	{
+
+	bDamroll = FALSE;
+	bHitroll = FALSE;
+
+	for (pObjAf = pObj->first_affect; pObjAf; pObjAf = pObjAf->next)
+	{
+		if (pObjAf->location == APPLY_DAMROLL)
+		{
+			pObjAf->level = level;
+			pObjAf->modifier = mod;
+			bDamroll = TRUE;
+		}
+		else if (pObjAf->location == APPLY_HITROLL)
+		{
+			pObjAf->level = level;
+			pObjAf->modifier = mod;
+			bHitroll = TRUE;
+		}
+	}
+
+	if (!bDamroll)
+	{
+		pAf = new_affect();
+		pAf->location = APPLY_DAMROLL;
+		pAf->modifier = mod;
+		pAf->where = TO_OBJECT;
+		pAf->type = -1;
+		pAf->duration = -1;
+		pAf->bitvector = 0;
+		pAf->level = level;
+		LINK(pAf, pObj->first_affect, pObj->last_affect, next, prev);
+	}
+
+	if (!bHitroll)
+	{
+		pAf = new_affect();
+		pAf->location = APPLY_HITROLL;
+		pAf->modifier = mod;
+		pAf->where = TO_OBJECT;
+		pAf->type = -1;
+		pAf->duration = -1;
+		pAf->bitvector = 0;
+		pAf->level = level;
+		LINK(pAf, pObj->first_affect, pObj->last_affect, next, prev);
+	}
+	}
+}
+
+void autoarmor(OBJ_INDEX_DATA * pObj)
+{
+	int size;
+	int level;
+
+	if (!pObj || pObj->item_type != ITEM_ARMOR)
+		return;
+
+	if (pObj->level < 1 || IS_OBJ_STAT(pObj, ITEM_QUEST))
+		return;
+
+	level = pObj->level;
+
+	size = UMAX(1, number_fuzzier(level) / 2 + 1);
+
+	pObj->value[0] = size;
+	pObj->value[1] = size;
+	pObj->value[2] = size;
+	pObj->value[3] = (size - 1);
+}
+
+void area_set_auto(AREA_DATA * pArea)
+{
+	OBJ_INDEX_DATA *pObjIndex;
+	MOB_INDEX_DATA *pMobIndex;
+	vnum_t vnum;
+
+	if (!pArea)
+		return;
+
+	for (vnum = pArea->min_vnum; vnum <= pArea->max_vnum; vnum++)
+	{
+		if ((pMobIndex = get_mob_index(vnum)) != NULL && pMobIndex->level >= 1)
+		{
+			if (pMobIndex->level < 9)
+				autoeasy(pMobIndex);
+			else if (pMobIndex->level < 30)
+				autoset(pMobIndex);
+			else
+				autohard(pMobIndex);
+		}
+
+		if ((pObjIndex = get_obj_index(vnum)) != NULL
+			&& !IS_OBJ_STAT(pObjIndex, ITEM_QUEST) && pObjIndex->level >= 1)
+		{
+
+			if (pObjIndex->item_type == ITEM_WEAPON)
+				autoweapon(pObjIndex);
+			else if (pObjIndex->item_type == ITEM_ARMOR)
+				autoarmor(pObjIndex);
+		}
+	}
+}
+
+CH_CMD(do_areaset)
+{
+	AREA_DATA *pArea;
+
+	if (!str_cmp(argument, "world"))
+	{
+		for (pArea = area_first; pArea; pArea = pArea->next)
+			area_set_auto(pArea);
+		chprintln(ch, "World set to default values.");
+	}
+	else if (ch->in_room != NULL && (pArea = ch->in_room->area) != NULL)
+	{
+		area_set_auto(pArea);
+		chprintlnf(ch, "%s set to default values.", pArea->name);
+	}
+	else
+		chprintln(ch, "Syntax: afun set world       - set the whole world.\n\r"
+				  "      : afun set             - set your current area.");
+
+	return;
 }
diff -ur src/olc.h new/olc.h
--- src/olc.h	Sat Mar 15 18:39:12 2003
+++ new/olc.h	Thu Mar 20 15:08:46 2003
@@ -277,6 +277,8 @@
 DECLARE_OLC_FUN(oedit_delete);
 DECLARE_OLC_FUN(oedit_addoprog);
 DECLARE_OLC_FUN(oedit_deloprog);
+DECLARE_OLC_FUN(oedit_autoweapon);
+DECLARE_OLC_FUN(oedit_autoarmor);
 
 /*
  * Mobile Editor Prototypes
@@ -287,6 +289,9 @@
 DECLARE_OLC_FUN(medit_group);	/* ROM */
 DECLARE_OLC_FUN(medit_addmprog);	/* ROM */
 DECLARE_OLC_FUN(medit_delmprog);	/* ROM */
+DECLARE_OLC_FUN(medit_autoset);
+DECLARE_OLC_FUN(medit_autoeasy);
+DECLARE_OLC_FUN(medit_autohard);
 
 /* Mobprog editor */
 DECLARE_OLC_FUN(mpedit_create);
@@ -417,5 +422,11 @@
 
 void sedit args((CHAR_DATA * ch, char *argument));
 SOCIAL_DATA *get_social_data args((const char *name));
+
+void autoset args((MOB_INDEX_DATA * pMob));
+void autohard args((MOB_INDEX_DATA * pMob));
+void autoeasy args((MOB_INDEX_DATA * pMob));
+void autoarmor args((OBJ_INDEX_DATA * pObj));
+void autoweapon args((OBJ_INDEX_DATA * pObj));
 
 #endif
diff -ur src/olc_act.c new/olc_act.c
--- src/olc_act.c	Sat Mar 15 18:39:12 2003
+++ new/olc_act.c	Thu Mar 20 15:08:46 2003
@@ -813,15 +813,16 @@
 	EDIT_AREA(ch, pArea);
 
 	chprintf(ch, "%s\n\r",
-			 stringf(0, ALIGN_CENTER, "-", "[ %s: %s ]", olc_ed_name(ch),
-					 olc_ed_vnum(ch)));
+			 stringf(0, ALIGN_CENTER, "-",
+					 FORMATF("[ %s: %s ]", olc_ed_name(ch), olc_ed_vnum(ch))));
 
 	chprintlnf(ch, "Name:     [%5d] %s", pArea->vnum, pArea->name);
 
 #if 0							/* ROM OLC */
 	chprintlnf(ch, "Recall:   [%5d] %s", pArea->recall,
-			   get_room_index(pArea->recall) ? get_room_index(pArea->recall)->
-			   name : "none");
+			   get_room_index(pArea->recall) ? get_room_index(pArea->
+															  recall)->name :
+			   "none");
 #endif							/* ROM */
 
 	chprintlnf(ch, "File:     %s", pArea->file_name);
@@ -1126,8 +1127,8 @@
 	buf1[0] = '\0';
 
 	strcat(buf1,
-		   stringf(0, ALIGN_CENTER, "-", "[ %s: %s ]", olc_ed_name(ch),
-				   olc_ed_vnum(ch)));
+		   stringf(0, ALIGN_CENTER, "-", FORMATF("[ %s: %s ]", olc_ed_name(ch),
+												 olc_ed_vnum(ch))));
 	strcat(buf1, "\n\r");
 
 	sprintf(buf, "Description:\n\r%s", pRoom->description);
@@ -2067,8 +2068,9 @@
 				   "[v4] Weight Mult [%ld]", obj->value[0],
 				   flag_string(container_flags, obj->value[1]),
 				   get_obj_index(obj->value[2]) ? get_obj_index(obj->value
-																[2])->short_descr
-				   : "none", obj->value[2], obj->value[3], obj->value[4]);
+																[2])->
+				   short_descr : "none", obj->value[2], obj->value[3],
+				   obj->value[4]);
 		break;
 
 	case ITEM_DRINK_CON:
@@ -2452,8 +2454,8 @@
 	EDIT_OBJ(ch, pObj);
 
 	chprintf(ch, "%s\n\r",
-			 stringf(0, ALIGN_CENTER, "-", "[ %s: %s ]", olc_ed_name(ch),
-					 olc_ed_vnum(ch)));
+			 stringf(0, ALIGN_CENTER, "-",
+					 FORMATF("[ %s: %s ]", olc_ed_name(ch), olc_ed_vnum(ch))));
 
 	chprintlnf(ch, "Name:        [%s]\n\rArea:        [%5d] %s",
 			   pObj->name, !pObj->area ? -1 : pObj->area->vnum,
@@ -2902,8 +2904,8 @@
 	EDIT_MOB(ch, pMob);
 
 	chprintf(ch, "%s\n\r",
-			 stringf(0, ALIGN_CENTER, "-", "[ %s: %s ]", olc_ed_name(ch),
-					 olc_ed_vnum(ch)));
+			 stringf(0, ALIGN_CENTER, "-",
+					 FORMATF("[ %s: %s ]", olc_ed_name(ch), olc_ed_vnum(ch))));
 
 	chprintlnf(ch, "Name:        [%s]\n\rArea:        [%5d] %s",
 			   pMob->player_name, !pMob->area ? -1 : pMob->area->vnum,
@@ -4535,7 +4537,7 @@
 
 CEDIT(cedit_create)
 {
-	int j, i = maxClan;
+	int j, i = maxClan, x;
 	CLAN_DATA *pClan;
 	struct clan_type *new_table;
 	char buf[MIL];
@@ -4564,6 +4566,12 @@
 	clan_table[i].name = str_dup(buf);
 	clan_table[i].who_name = str_dup(buf);
 
+	for (x = 0; x < MAX_RANK; x++)
+	{
+		clan_table[i].rank[x].shortname = str_dup("---");
+		clan_table[i].rank[x].rankname = str_dup("Member");
+	}
+
 	pClan = &clan_table[i];
 	edit_start(ch, pClan, ED_CLAN);
 	chprintln(ch, "Clan created.");
@@ -4592,6 +4600,7 @@
 		int nMatch = 0;
 		ROOM_INDEX_DATA *pRoom;
 		vnum_t vnum;
+		MBR_DATA *pmbr, *next = NULL;
 
 		alloc_mem(new_table, struct clan_type, maxClan);
 
@@ -4603,6 +4612,19 @@
 
 		c = clan_lookup(pClan->name);
 
+		for (pmbr = mbr_first; pmbr != NULL; pmbr = next)
+		{
+			next = pmbr->next;
+
+			if (pmbr->clan == c)
+			{
+				UNLINK(pmbr, mbr_first, mbr_last, next, prev);
+				free_mbr(pmbr);
+			}
+			else if (pmbr->clan > c)
+				pmbr->clan -= 1;
+		}
+
 		for (pch = char_first; pch != NULL; pch = pch->next)
 		{
 			if (pch->clan == c)
@@ -4641,6 +4663,124 @@
 		edit_start(ch, pClan, ED_CLAN);
 		chprintln(ch, "Clan deleted.");
 	}
+
+	return TRUE;
+}
+
+OEDIT(oedit_autoweapon)
+{
+	OBJ_INDEX_DATA *pObj;
+
+	EDIT_OBJ(ch, pObj);
+
+	if (pObj->item_type != ITEM_WEAPON)
+	{
+		chprintln(ch, " {rAutoweapon only works on weapons...{x");
+		return FALSE;
+	}
+
+	if (pObj->level < 1)
+	{
+		chprintlnf
+			(ch,
+			 " {cAutoweapon requires a level to be set on the weapon first(vnum %ld).{x",
+			 pObj->vnum);
+		return FALSE;
+	}
+
+	if (IS_OBJ_STAT(pObj, ITEM_QUEST))
+	{
+		chprintln(ch, "This weapon cannot be autoset.");
+		return FALSE;
+	}
+
+	autoweapon(pObj);
+	chprintln(ch, "Weapon set to default values., check for accuracy.");
+
+	return TRUE;
+}
+
+OEDIT(oedit_autoarmor)
+{
+	OBJ_INDEX_DATA *pObj;
+
+	EDIT_OBJ(ch, pObj);
+
+	if (pObj->item_type != ITEM_ARMOR)
+	{
+		chprintln(ch, " {rAutoArmor only works on Armor ...{x");
+		return FALSE;
+	}
+
+	if (pObj->level < 1)
+	{
+		chprintlnf
+			(ch,
+			 " {cAutoArmor requires a level to be set on the armor first.(vnum %ld){x",
+			 pObj->vnum);
+		return FALSE;
+	}
+
+	if (IS_OBJ_STAT(pObj, ITEM_QUEST))
+	{
+		chprintln(ch, "This weapon cannot be autoset.");
+		return FALSE;
+	}
+
+	autoarmor(pObj);
+	chprintln(ch, "AutoArmor has set experimental values for AC.{x");
+	return TRUE;
+}
+
+MEDIT(medit_autoset)
+{
+	MOB_INDEX_DATA *pMob;
+
+	EDIT_MOB(ch, pMob);
+
+	if (pMob->level < 1)
+	{
+		chprintlnf(ch, "Set a level on the mob first!!!(vnum %ld)", pMob->vnum);
+		return FALSE;
+	}
+
+	autoset(pMob);
+	chprintln(ch, " Values set, check for accuracy.");
+	return TRUE;
+}
+
+MEDIT(medit_autohard)
+{
+	MOB_INDEX_DATA *pMob;
+
+	EDIT_MOB(ch, pMob);
+
+	if (pMob->level < 1)
+	{
+		chprintlnf(ch, "Set a level on the mob first!!!(vnum %ld)", pMob->vnum);
+		return FALSE;
+	}
+
+	autohard(pMob);
+
+	chprintln(ch, " Hard values set, check for accuracy.");
+
+	return TRUE;
+}
+
+MEDIT(medit_autoeasy)
+{
+	MOB_INDEX_DATA *pMob;
+
+	EDIT_MOB(ch, pMob);
+	if (pMob->level < 1)
+	{
+		chprintlnf(ch, "Set a level on the mob first!!!(vnum %ld)", pMob->vnum);
+		return FALSE;
+	}
+	autoeasy(pMob);
+
+	chprintln(ch, " Easy values set, check for accuracy.");
 
 	return TRUE;
 }
diff -ur src/olc_save.c new/olc_save.c
--- src/olc_save.c	Sat Mar 15 18:39:12 2003
+++ new/olc_save.c	Thu Mar 20 15:08:46 2003
@@ -77,7 +77,7 @@
 	int i;
 	int o;
 
-	if (str == NULL)
+	if (str == NULL || !str_cmp(str, "(null)"))
 		return '\0';
 
 	for (o = i = 0; str[i + o] != '\0'; i++)
diff -ur src/olc_social.c new/olc_social.c
--- src/olc_social.c	Sat Mar 15 18:39:12 2003
+++ new/olc_social.c	Thu Mar 20 15:08:46 2003
@@ -87,8 +87,8 @@
 	}
 
 	chprintf(ch, "%s\n\r",
-			 stringf(0, ALIGN_CENTER, "-", "[ %s: %s ]", olc_ed_name(ch),
-					 olc_ed_vnum(ch)));
+			 stringf(0, ALIGN_CENTER, "-",
+					 FORMATF("[ %s: %s ]", olc_ed_name(ch), olc_ed_vnum(ch))));
 
 	chprintf(ch, "Name    : %s\n\r"
 			 "(cnoarg): %s\n\r" "(onoarg): %s\n\r"
diff -ur src/proto.h new/proto.h
--- src/proto.h	Sat Mar 15 18:39:12 2003
+++ new/proto.h	Thu Mar 20 15:08:46 2003
@@ -62,13 +62,12 @@
 const char *draw_line args((char *fill, int len));
 const char *smash_colour args((const char *str));
 const char *stringf
-args((int length, int align, const char *fill,
-	  const char *string, ...)) __attribute__ ((format(printf, 4, 5)));
+args((int length, int align, const char *fill, const char *string));
 bool is_ansi_printed_char args((char c));
 
 void public_ch args((CHAR_DATA * ch, const char *argument,
 					 const char *type, flag_t bitname,
-					 enum special_flags spec_flag));
+					 enum special_flags spec_flag, int last_type));
 
 /* act_enter.c */
 RID *get_random_room args((CHAR_DATA * ch));
@@ -119,6 +118,10 @@
 	  const void *arg2, flag_t type, int min_pos));
 void perform_act args((const char *orig, CHAR_DATA * ch, const void *arg1,
 					   const void *arg2, flag_t type, CHAR_DATA * to));
+const char *perform_act_string
+args(
+	 (const char *orig, CHAR_DATA * ch, const void *arg1, const void *arg2,
+	  bool cReturn));
 
 void chprintf args((CHAR_DATA *, char *, ...))
 	__attribute__ ((format(printf, 2, 3)));
@@ -159,6 +162,7 @@
 const char *str_dup args((const char *str));
 void free_string args((const char *pstr));
 int number_fuzzy args((int number));
+int number_fuzzier args((int number));
 int number_range args((int from, int to));
 int number_percent args((void));
 int number_door args((void));
@@ -557,6 +561,14 @@
 int sort_socials args((void));
 int sort_helps args((void));
 int srt_skills args((const void *p1, const void *p2));
+
+char *FORMATF args((const char *formatbuf, ...))
+	__attribute__ ((format(printf, 1, 2)));
+void *alloc_perm args((size_t sMem));
+
+void save_members args((void));
+void update_members args((CHAR_DATA * ch, bool pdelete));
+void load_members args((void));
 
 #undef	CD
 #undef	MID
diff -ur src/recycle.c new/recycle.c
--- src/recycle.c	Sat Mar 15 18:39:12 2003
+++ new/recycle.c	Thu Mar 20 15:08:46 2003
@@ -304,6 +304,33 @@
 	return;
 }
 
+void clear_history(PC_DATA * pcdata)
+{
+	int i;
+	int x;
+
+	for (i = 0; i < LAST_MAX; i++)
+	{
+		for (x = 0; x < LAST_PAGE_LENGTH; x++)
+		{
+			pcdata->history[i][x] = &str_empty[0];
+		}
+	}
+}
+
+void free_history(PC_DATA * pcdata)
+{
+	int i, x;
+
+	for (i = 0; i < LAST_MAX; i++)
+	{
+		for (x = 0; x < LAST_PAGE_LENGTH; x++)
+		{
+			free_string(pcdata->history[i][x]);
+		}
+	}
+}
+
 PC_DATA *new_pcdata(void)
 {
 	int alias, bud;
@@ -326,6 +353,7 @@
 		pcdata->buddies[bud] = NULL;
 	}
 
+	clear_history(pcdata);
 	pcdata->buffer = new_buf();
 	alloc_mem(pcdata->learned, int, maxSkill);
 	alloc_mem(pcdata->group_known, bool, maxGroup);
@@ -357,6 +385,9 @@
 	}
 	for (pos = 0; pos < MAX_BUDDY; pos++)
 		free_string(pcdata->buddies[pos]);
+
+	free_history(pcdata);
+
 	INVALIDATE(pcdata);
 
 	PUT_FREE(pcdata, next, pcdata_free);
@@ -698,4 +729,30 @@
 	INVALIDATE(pwd);
 
 	PUT_FREE(pwd, next, WPWD_free);
+}
+
+MBR_DATA *new_mbr(void)
+{
+	static MBR_DATA mbr_zero;
+	MBR_DATA *mbr;
+
+	GET_FREE(mbr, MBR_DATA, next, mbr_free);
+
+	*mbr = mbr_zero;
+	mbr->name = &str_empty[0];
+	mbr->clan = -1;
+	mbr->rank = 0;
+	VALIDATE(mbr);
+	return mbr;
+}
+
+void free_mbr(MBR_DATA * mbr)
+{
+	if (!IS_VALID(mbr))
+		return;
+
+	free_string(mbr->name);
+
+	INVALIDATE(mbr);
+	PUT_FREE(mbr, next, mbr_free);
 }
diff -ur src/recycle.h new/recycle.h
--- src/recycle.h	Sat Mar 15 18:39:12 2003
+++ new/recycle.h	Thu Mar 20 15:08:46 2003
@@ -44,7 +44,7 @@
   } \
   else \
   { \
-    alloc_mem(point, type, 1); \
+    point = (type *)alloc_perm(sizeof(*point)); \
   }\
   memset(point, 0, sizeof(*point)); \
 } while(0)
@@ -143,5 +143,8 @@
 
 void free_pwd args((WPWD_DATA * pwd));
 WPWD_DATA *new_pwd args((void));
+
+MBR_DATA *new_mbr args((void));
+void free_mbr args((MBR_DATA * mbr));
 
 #endif
diff -ur src/save.c new/save.c
--- src/save.c	Sat Mar 15 18:39:12 2003
+++ new/save.c	Thu Mar 20 15:08:46 2003
@@ -588,6 +588,7 @@
 	ch->pcdata->board = &boards[DEFAULT_BOARD];
 	ch->info_settings = INFO_QUIET;	/* this actually turns quiet off */
 	ch->pcdata->pwd = str_dup("");
+	ch->pcdata->webpass = str_dup("");
 	ch->pcdata->bamfin = str_dup("");
 	ch->pcdata->bamfout = str_dup("");
 	ch->pcdata->title = str_dup("");
diff -ur src/string.c new/string.c
--- src/string.c	Sat Mar 15 18:39:12 2003
+++ new/string.c	Thu Mar 20 15:08:46 2003
@@ -1004,36 +1004,23 @@
 	return (result);
 }
 
-const char *stringf(int length, int align,
-					const char *fill, const char *string, ...)
+const char *stringf(int length, int align, const char *fill, const char *string)
 {
-	char buf[MSL];
-	char buf2[MSL];
-	char *fmt;
-	char fmt2[MSL];
-	char *new_string;
-	char *count_string;
+	const char *count_string;
 	char temp;
 	int count = 0, nCount = 0;
 	int pos = 0;
-	va_list args;
-
+	char *result;
 	static char buf_new[5][MSL];
 	static int i;
-	char *result = buf_new[i];
 
 	// rotate buffers
 	++i;
 	i %= 5;
 
-	fmt = fmt2;
-	va_start(args, string);
-	vsnprintf(fmt2, MSL, string, args);
-	va_end(args);
+	result = buf_new[i];
 
-	new_string = buf;
-	count_string = buf2;
-	strcpy(buf2, fmt);
+	count_string = string;
 
 	if (!fill)
 		fill = " ";
@@ -1062,7 +1049,7 @@
 		count = (length - ++nCount);
 		while (nCount++ <= length)
 		{
-			buf[pos++] = *fill;
+			result[pos++] = *fill;
 		}
 	}
 
@@ -1072,18 +1059,18 @@
 		count = nCount;
 		while (nCount-- > 0)
 		{
-			buf[pos++] = *fill;
+			result[pos++] = *fill;
 		}
 	}
 
-	while (*fmt && count != length)
+	while (*string && count != length)
 	{
-		temp = *fmt++;
-		buf[pos++] = temp;
+		temp = *string++;
+		result[pos++] = temp;
 
 		if (temp == ANSI_KEY)
 		{
-			temp = buf[pos] = *fmt++;
+			temp = result[pos] = *string++;
 
 			if (is_ansi_printed_char(temp))
 				count++;
@@ -1095,10 +1082,9 @@
 	}
 
 	while (count++ < length)
-		buf[pos++] = *fill;
+		result[pos++] = *fill;
 
-	buf[pos] = '\0';
-	strcpy(result, new_string);
+	result[pos] = '\0';
 	return (result);
 }
 
@@ -1282,4 +1268,20 @@
 	ch->pcdata->str_ed_key = argument[0];
 	chprintlnf(ch, "The string editor now uses %c for commands.",
 			   STR_EDIT_KEY(ch));
+}
+
+char *FORMATF(const char *formatbuf, ...)
+{
+	static int i;
+	static char buf[10][MSL * 3];
+	va_list args;
+
+	++i;
+	i %= 10;
+
+	va_start(args, formatbuf);
+	vsnprintf(buf[i], MSL * 3, formatbuf, args);
+	va_end(args);
+
+	return buf[i];
 }
diff -ur src/tablesave.c new/tablesave.c
--- src/tablesave.c	Sat Mar 15 18:39:12 2003
+++ new/tablesave.c	Thu Mar 20 15:08:46 2003
@@ -80,6 +80,7 @@
 GQUEST gq;
 DEITY_DATA deity;
 WPWD_DATA pwd;
+MBR_DATA mbr;
 
 const char *do_fun_name(DO_FUN *);
 DO_FUN *do_fun_lookup(const char *);
@@ -187,6 +188,26 @@
 	return !str_cmp(arg, "") || blah != NULL;
 }
 
+const char *clan_str(void *temp)
+{
+	int *clan = (int *) temp;
+
+	return clan_table[*clan].name;
+}
+
+bool clan_read(void *temp, char *arg)
+{
+	int *posic = (int *) temp;
+	int ffg = clan_lookup(arg);
+
+	*posic = UMAX(0, ffg);
+
+	if (ffg == -1)
+		return FALSE;
+	else
+		return TRUE;
+}
+
 const struct savetable_type cmdsavetable[] = {
 	{"name", FIELD_STRING, (void *) &cmd.name, NULL, NULL},
 
@@ -357,6 +378,15 @@
 	{NULL, 0, NULL, NULL, NULL}
 };
 
+const struct savetable_type mbrsavetable[] = {
+	{"name", FIELD_STRING, (void *) &mbr.name, NULL, NULL},
+	{"clan", FIELD_FUNCION_INT_TO_STR, (void *) &mbr.clan, (void *) clan_str,
+	 (void *) clan_read},
+	{"rank", FIELD_INT, (void *) &mbr.rank, NULL, NULL},
+	{"level", FIELD_INT, (void *) &mbr.level, NULL, NULL},
+	{NULL, 0, NULL, NULL, NULL}
+};
+
 void load_struct(FILE * fp, void *typebase,
 				 const struct savetable_type *table, void *puntero)
 {
@@ -613,7 +643,7 @@
 				(const char **) ((int) temp->puntero_field - (int) typebase +
 								 (int) puntero);
 			fprintf(fp, "%s\t\t%s~\n", temp->field,
-					IS_NULLSTR(*pstring) ? "" : *pstring);
+					IS_NULLSTR(*pstring) ? "" : fix_string(*pstring));
 			break;
 
 		case FIELD_INT:
@@ -708,7 +738,8 @@
 								 (int) puntero);
 			fprintf(fp, "%s\t\t", temp->field);
 			for (i = 0; i < (int) temp->argument; i++)
-				fprintf(fp, "%s~ ", !IS_NULLSTR(pstring[i]) ? pstring[i] : "");
+				fprintf(fp, "%s~ ",
+						!IS_NULLSTR(pstring[i]) ? fix_string(pstring[i]) : "");
 			fprintf(fp, "@~\n");
 			break;
 
@@ -719,7 +750,8 @@
 			fprintf(fp, "%s\t\t", temp->field);
 			for (i = 0; i < (int) temp->argument && !IS_NULLSTR(pstring[i]);
 				 i++)
-				fprintf(fp, "%s~ ", !IS_NULLSTR(pstring[i]) ? pstring[i] : "");
+				fprintf(fp, "%s~ ",
+						!IS_NULLSTR(pstring[i]) ? fix_string(pstring[i]) : "");
 			fprintf(fp, "@~\n");
 			break;
 
@@ -744,7 +776,8 @@
 			{
 				fprintf(fp, "%s\t%s%d ", temp->field,
 						strlen(temp->field) < 8 ? "\t" : "", i + 1);
-				fprintf(fp, "%s~ %s~\n", rdata[i].shortname, rdata[i].rankname);
+				fprintf(fp, "%s~ %s~\n", fix_string(rdata[i].shortname),
+						fix_string(rdata[i].rankname));
 			}
 			break;
 
@@ -1714,6 +1747,79 @@
 		ppwd = new_pwd();
 		load_struct(fp, &pwd, pwdsavetable, ppwd);
 		LINK(ppwd, wpwd_first, wpwd_last, next, prev);
+	}
+	file_close(fp);
+}
+
+void save_members(void)
+{
+	MBR_DATA *pmbr;
+	FILE *fp;
+#if !defined(WIN32)
+	char *TEMPFILE = MBR_FILE ".tmp";
+
+	if ((fp = file_open(TEMPFILE, "w")) == NULL)
+#else
+	if ((fp = file_open(MBR_FILE, "w")) == NULL)
+#endif
+	{
+		perror(MBR_FILE);
+		file_close(fp);
+		return;
+	}
+
+	for (pmbr = mbr_first; pmbr != NULL; pmbr = pmbr->next)
+	{
+		if (pmbr->clan < 0 || pmbr->clan >= maxClan)
+		{
+			bugf("%s member data invalid.", pmbr->name);
+			continue;
+		}
+		fprintf(fp, "#MBR\n");
+		save_struct(fp, &mbr, mbrsavetable, pmbr);
+		fprintf(fp, "#END\n\n");
+	}
+
+	fprintf(fp, "#!\n");
+
+	file_close(fp);
+
+#if !defined(WIN32)
+	rename(TEMPFILE, MBR_FILE);
+#endif
+}
+
+void load_members(void)
+{
+	FILE *fp;
+	MBR_DATA *pmbr;
+	const char *word;
+
+	fp = file_open(MBR_FILE, "r");
+
+	if (!fp)
+	{
+		bug("Unable to open " MBR_FILE " to load members.", 0);
+		save_members();
+		return;
+	}
+
+	for (;;)
+	{
+		word = fread_word(fp);
+
+		if (!str_cmp(word, "#!"))
+			break;
+
+		if (str_cmp(word, "#MBR"))
+		{
+			bugf("word doesn't exist (%s)", word);
+			exit(1);
+		}
+
+		pmbr = new_mbr();
+		load_struct(fp, &mbr, mbrsavetable, pmbr);
+		LINK(pmbr, mbr_first, mbr_last, next, prev);
 	}
 	file_close(fp);
 }
diff -ur src/webserver.c new/webserver.c
--- src/webserver.c	Sat Mar 15 18:39:12 2003
+++ new/webserver.c	Thu Mar 20 15:08:46 2003
@@ -119,7 +119,6 @@
 CH_CMD(do_webpass)
 {
 	char arg1[MIL];
-	char arg2[MIL];
 	char *pArg;
 	char *pwdnew;
 	char *p;
@@ -153,49 +152,22 @@
 	}
 	*pArg = '\0';
 
-	pArg = arg2;
-	while (isspace(*argument))
-		argument++;
-
-	cEnd = ' ';
-	if (*argument == '\'' || *argument == '\"')
-		cEnd = *argument++;
-
-	while (*argument != '\0')
+	if (IS_NULLSTR(arg1))
 	{
-		if (*argument == cEnd)
-		{
-			argument++;
-			break;
-		}
-		*pArg++ = *argument++;
-	}
-	*pArg = '\0';
-
-	if (IS_NULLSTR(arg1) || IS_NULLSTR(arg2))
-	{
-		chprintln(ch, "Syntax: webpass <old> <new>.");
+		chprintln(ch, "Syntax: webpass <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)
+	if (strlen(arg1) < 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);
+	pwdnew = crypt(arg1, ch->name);
 	for (p = pwdnew; *p != '\0'; p++)
 	{
 		if (*p == '~')
@@ -1198,8 +1170,8 @@
 		else if (victim->in_room == victim->fighting->in_room)
 		{
 			strcat(buf,
-				   IS_NPC(victim) ? victim->fighting->
-				   short_descr : victim->fighting->name);
+				   IS_NPC(victim) ? victim->fighting->short_descr : victim->
+				   fighting->name);
 			strcat(buf, ".");
 		}
 		else