SmaugWizard/Backup/
SmaugWizard/Backup/L/
SmaugWizard/Boards/
SmaugWizard/Building/
SmaugWizard/Corpses/
SmaugWizard/Councils/
SmaugWizard/Deity/
SmaugWizard/Gods/
SmaugWizard/MudProgs/
SmaugWizard/Player/L/
SmaugWizard/Src/
SmaugWizard/Src/res/
/****************************************************************************
 * [S]imulated [M]edieval [A]dventure multi[U]ser [G]ame      |				*
 * -----------------------------------------------------------|   \\._.//	*
 * SmaugWiz (C) 1998 by Russ Pillsbury (Windows NT version)   |   (0...0)	*
 * -----------------------------------------------------------|    ).:.(	*
 * SMAUG (C) 1994, 1995, 1996 by Derek Snider                 |    {o o}	*
 * -----------------------------------------------------------|   / ' ' \	*
 * SMAUG code team: Thoric, Altrag, Blodkai, Narn, Haus,      |~'~.VxvxV.~'~*
 * Scryn, Swordbearer, Rennard, Tricops, and Gorog.           |				*
 * ------------------------------------------------------------------------ *
 * Merc 2.1 Diku Mud improvments copyright (C) 1992, 1993 by Michael        *
 * Chastain, Michael Quan, and Mitchell Tse.                                *
 * Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,          *
 * Michael Seifert, Hans Henrik Staerfeldt, Tom Madsen, and Katja Nyboe.    *
 ****************************************************************************/

#include	"stdafx.h"
#include	"smaug.h"
#include	"Smaugx.h"
#include	"language.h"
#include	"skill.h"
#include	"objects.h"
#include	"rooms.h"
#include	"clans.h"
#include	"class.h"
#include	"races.h"
#include	"Exits.h"
#include	"SmaugWizDoc.h"
#include	"SmaugFiles.h"
#include	"descriptor.h"
#include	"character.h"

#define MAX_NEST	100
static	CObjData *	rgObjNest	[MAX_NEST];

CCouncilData	*first_council;
CCouncilData	*last_council;

// local routines
void	MakeClanGuildOrOrder (CCharacter& Ch, char *name, ClanTypes type);
void	SetclanGuildOrOrder (CCharacter& Ch, char *argument, ClanTypes type);
void	ShowClanGuildOrOrder (CCharacter& Ch, const char *name, ClanTypes type);
BOOL	load_clan_file (char *clanfile);

void	fread_council (CCouncilData *council, FILE *fp);
BOOL	load_council_file (char *councilfile);
void	write_council_list ();


// Load in all the clan files.
void load_clans ()
{
	FILE	*fp;
	char	*pFname, *pLine;

	gpDoc->LogString ("Loading clans...", LOG_BOOT);

	fclose (fpReserve);
	if (! (fp = fopen (FileTable.GetName (SM_CLAN_LIST), "r"))) {
		perror (FileTable.GetName (SM_CLAN_LIST));
		ThrowSmaugException (SE_CLANS);
	}

	while (! feof (fp)) {
		pLine = fread_line (fp);
		pFname = ParseLine (pLine);
		if (pFname [0] == '$') then break;
		gpDoc->LogString (pFname, LOG_BOOT);

		if (! load_clan_file (pFname))
			bug ("Cannot load clan file: %s", pFname);
	}
	fclose (fp);

	fpReserve = fopen (FileTable.GetName (SM_NULL_FILE), "r");
}


CClanData::CClanData (const char* name, const char* fname, ClanTypes type)
{
	memset (this, 0, sizeof (CClanData));
	SetName (name);
	SetFilename (fname);
	SetType (type);
	motto = STRALLOC ("");
	SetDescription ("");
	deity = STRALLOC ("");
	leader = STRALLOC ("");
	number1 = STRALLOC ("");
	number2 = STRALLOC ("");
}


// Save a clan's data to its data file
void CClanData::Save ()
{
	FILE	*fp;

	CString Fname = FileTable.MakeName (SD_CLAN_DIR, m_pFilename);

	fclose (fpReserve);
	if ((fp = fopen (Fname, "w")) == NULL)
		bug ("CClanData::Save: fopen. Filename = %s", NCCP Fname);

	else {
		fprintf (fp, "#CLAN\n");
		fprintf (fp, "Name         %s~\n",	m_pName);
		fprintf (fp, "Filename     %s~\n",	m_pFilename);
		fprintf (fp, "Type         %d\n",	m_Type);
		fprintf (fp, "Motto        %s~\n",	motto);
		fprintf (fp, "Description  %s~\n",	m_pDescription);
		fprintf (fp, "Deity        %s~\n",	deity);
		fprintf (fp, "Leader       %s~\n",	leader);
		fprintf (fp, "NumberOne    %s~\n",	number1);
		fprintf (fp, "NumberTwo    %s~\n",	number2);
		fprintf (fp, "PKills       %d\n",	pkills);
		fprintf (fp, "PDeaths      %d\n",	pdeaths);
		fprintf (fp, "MKills       %d\n",	mkills);
		fprintf (fp, "MDeaths      %d\n",	mdeaths);
		fprintf (fp, "IllegalPK    %d\n",	illegal_pk);
		fprintf (fp, "Score        %d\n",	score);
		fprintf (fp, "Class        %d\n",	m_Class);
		fprintf (fp, "Favour       %d\n",	favour);
		fprintf (fp, "Strikes      %d\n",	strikes);
		fprintf (fp, "Members      %d\n",	m_Members);
		fprintf (fp, "Alignment    %d\n",	alignment);
		fprintf (fp, "Board        %d\n",	board);
		fprintf (fp, "ClanObjOne   %d\n",	clanobj1);
		fprintf (fp, "ClanObjTwo   %d\n",	clanobj2);
		fprintf (fp, "ClanObjThree %d\n",	clanobj3);
		fprintf (fp, "Recall       %d\n",	recall);
		fprintf (fp, "Storeroom    %d\n",	storeroom);
		fprintf (fp, "GuardOne     %d\n",	guard1);
		fprintf (fp, "GuardTwo     %d\n",	guard2);
		fprintf (fp, "End\n\n");
		fprintf (fp, "#END\n");
	}
	fclose (fp);
	fpReserve = fopen (FileTable.GetName (SM_NULL_FILE), "r");
}


// Read in actual clan data.
#if defined (KEY)
#undef KEY
#endif

#define KEY(literal,field,value)					\
				if (!str_cmp (word, literal)) {		\
				    field  = value;					\
				    fMatch = TRUE;					\
				    break;							\
				}

void CClanData::Read (FILE *fp)
{
	char	*word, *pLine;
	BOOL	fMatch;

	for (;;) {
		fMatch = FALSE;
		if (! feof (fp)) {
			pLine = fread_line (fp);
			word = ParseWord (pLine);
		}
		else word = "End";

		switch  (UPPER (word [0])) {
		  case '*':
			fMatch = TRUE;
			break;

		  case 'A':
			KEY ("Alignment",	alignment,	ParseNumber (pLine));
			break;

		  case 'B':
			KEY ("Board",		board,		ParseNumber (pLine));
			break;

		  case 'C':
			KEY ("ClanObjOne",	clanobj1,		ParseNumber (pLine));
			KEY ("ClanObjTwo",	clanobj2,		ParseNumber (pLine));
			KEY ("ClanObjThree",clanobj3,		ParseNumber (pLine));
			KEY ("Class",		m_Class,		ParseNumber (pLine));
			break;

		  case 'D':
			KEY ("Deity",		deity,			ParseString (pLine, fp));
			KEY ("Description",	m_pDescription,	ParseString (pLine, fp));
			break;

		  case 'E':
			if (!str_cmp (word, "End")) {
				if (! GetName ())
					SetName ("");
				if (! leader)
					leader = STRALLOC ("");
				if (! GetDescription ())
					SetDescription ("");
				if (! motto)
					motto = STRALLOC ("");
				if (! number1)
					number1 = STRALLOC ("");
				if (! number2)
					number2 = STRALLOC ("");
				if (! deity)
					deity = STRALLOC ("");
				return;
			}
			break;

		  case 'F':
			KEY ("Favour",		favour,			ParseNumber (pLine));
			KEY ("Filename",	m_pFilename,	ParseStringNohash (pLine, fp));

		  case 'G':
			KEY ("GuardOne",	guard1,			ParseNumber (pLine));
			KEY ("GuardTwo",	guard2,			ParseNumber (pLine));
			break;

		  case 'I':
			KEY ("IllegalPK",	illegal_pk,		ParseNumber (pLine));
			break;

		  case 'L':
			KEY ("Leader",		leader,			ParseString (pLine, fp));
			break;

		  case 'M':
			KEY ("MDeaths",		mdeaths,		ParseNumber (pLine));
			KEY ("Members",		m_Members,		ParseNumber (pLine));
			KEY ("MKills",		mkills,			ParseNumber (pLine));
			KEY ("Motto",		motto,			ParseString (pLine, fp));
			break;

		  case 'N':
			KEY ("Name",		m_pName,		ParseString (pLine, fp));
			KEY ("NumberOne",	number1,		ParseString (pLine, fp));
			KEY ("NumberTwo",	number2,		ParseString (pLine, fp));
			break;

		  case 'P':
			KEY ("PDeaths",		pdeaths,		ParseNumber (pLine));
			KEY ("PKills",		pkills,			ParseNumber (pLine));
			break;

		  case 'R':
			KEY ("Recall",		recall,			ParseNumber (pLine));
			break;

		  case 'S':
			KEY ("Score",		score,			ParseNumber (pLine));
			KEY ("Strikes",		strikes,		ParseNumber (pLine));
			KEY ("Storeroom",	storeroom,		ParseNumber (pLine));
			break;

		  case 'T':
			KEY ("Type",		m_Type,		(ClanTypes)ParseNumber (pLine));
			break;
		}

		if (! fMatch)
			bug ("CClanData::Read: no match: %s", word);
	}
}


CClanData::~CClanData ()
{
	delete m_pFilename;
}


void do_makeclan (CCharacter *ch, char *argument)
{
	MakeClanGuildOrOrder (*ch, argument, CLAN_PLAIN);
}


void do_makeguild (CCharacter *ch, char *argument)
{
	MakeClanGuildOrOrder (*ch, argument, CLAN_GUILD);
}


void do_makeorder (CCharacter *ch, char *argument)
{
	MakeClanGuildOrOrder (*ch, argument, CLAN_ORDER);
}


void MakeClanGuildOrOrder (CCharacter& Ch, char *name, ClanTypes type)
{
	CClanData	*clan;

	char	*tname = ClanList.GetTypeName (type);

	if (! name || name [0] == '\0') {
		Ch.SendTextf ("Usage: make%s <%s name>\n\r", tname, tname);
		return;
	}

	CString	Fname = name;
	if (Fname.Find ('.') >= 0) {
		Ch.SendText ("Use name of Clan, Guild or Order. Not filename\n\r");
		return;
	}

	POSITION	pos = ClanList.GetHeadPosition ();
	while (pos) {
		CClanData	&Cl = *ClanList.GetNext (pos);
		if (Cl.GetType () == type && ! stricmp (Cl.GetName (), name)) {
			Ch.SendTextf ("%s: %s Already Exists as %s.\n\r", tname, name,
				Cl.GetFilename ());
			return;
		}
	}

	Fname += '.';
	Fname += tname;

	clan = new CClanData (name, Fname, type);
	ClanList.AddTail (clan);
	clan->Save ();
	ClanList.Write ();
}



void do_showclan (CCharacter *ch, char *argument)
{
	ShowClanGuildOrOrder (*ch, argument, CLAN_PLAIN);
}


void do_showguild (CCharacter *ch, char *argument)
{
	ShowClanGuildOrOrder (*ch, argument, CLAN_GUILD);
}


void do_showorder (CCharacter *ch, char *argument)
{
	ShowClanGuildOrOrder (*ch, argument, CLAN_ORDER);
}


void ShowClanGuildOrOrder (CCharacter& Ch, const char *name, ClanTypes type)
{   
	CClanData	*clan;

	if (Ch.IsNpc ()) {
		Ch.SendText ("Huh?\n\r");
		return;
	}

	char	*tname = ClanList.GetTypeName (type);

	if (name [0] == '\0') {
		Ch.SendTextf ("Usage: show%s <%s name>\n\r", tname, tname);
		return;
	}

	clan = ClanList.Find (name, type);
	if (! clan) {
		Ch.SendTextf ("No such %s.\n\r", tname);
		return;
	}

	Ch.SendTextf ("%s      : %s\n\rFilename: %s\n\rMotto   : %s\n\r",
		tname, clan->GetName (), clan->GetFilename (), clan->motto);

	Ch.SendTextf ("Description: %s\n\rDeity: %s\n\rLeader: %s\n\r",
		clan->GetDescription (), clan->deity, clan->leader);

	Ch.SendTextf ("Number1: %s\n\rNumber2: %s\n\rPKills: %6d    "
		"PDeaths: %6d\n\r",
		clan->number1, clan->number2, clan->pkills, clan->pdeaths);

	Ch.SendTextf ("MKills: %6d    MDeaths: %6d\n\r",
		clan->mkills, clan->mdeaths);

	Ch.SendTextf ("IllegalPK: %-6d Score: %d\n\r",
		clan->illegal_pk, clan->score);

	Ch.SendTextf ("Favour: %6d  Strikes: %d\n\r",
		clan->favour, clan->strikes);

	Ch.SendTextf ("Members: %3d   Alignment: %d  Class: %d\n\r",
		clan->GetMembers (), clan->alignment, clan->m_Class);

	Ch.SendTextf ("Board: %5d     Object1: %5d Object2: %5d Object3: %5d\n\r",
		clan->board, clan->clanobj1, clan->clanobj2, clan->clanobj3);

	Ch.SendTextf ("Recall: %5d  Storeroom: %5d  Guard1: %5d  Guard2: %5d\n\r",
		clan->recall, clan->storeroom, clan->guard1, clan->guard2);
}


void do_setclan (CCharacter *ch, char *argument)
{
	SetclanGuildOrOrder (*ch, argument, CLAN_PLAIN);
}


void do_setguild (CCharacter *ch, char *argument)
{
	SetclanGuildOrOrder (*ch, argument, CLAN_GUILD);
}


void do_setorder (CCharacter *ch, char *argument)
{
	SetclanGuildOrOrder (*ch, argument, CLAN_ORDER);
}


void SetclanGuildOrOrder (CCharacter& Ch, char *argument, ClanTypes type)
{
	char		arg1 [MAX_INPUT_LENGTH];
	char		arg2 [MAX_INPUT_LENGTH];
	CClanData	*clan;

	if (Ch.IsNpc ()) {
		Ch.SendText ("Huh?\n\r");
		return;
	}

	char	*tname = ClanList.GetTypeName (type);

	argument = one_argument (argument, arg1);
	argument = one_argument (argument, arg2);

	if (arg1 [0] == '\0') {
		Ch.SendText ("Usage: setclan <clan> <field>\n\r");
		Ch.SendText ("\n\rField being one of:\n\r");
		Ch.SendText (" deity leader number1 number2\n\r"); 
		Ch.SendText (" members board recall storage\n\r");
		Ch.SendText (" align");	
		Ch.SendText (" obj1 obj2 obj3 guard1 guard2\n\r");
		if (Ch.GetTrustLevel () >= LEVEL_SUB_IMPLEM) {
			Ch.SendText (" name filename motto desc\n\r");
			Ch.SendText (" favour strikes delete\n\r");
		}
		return;
	}

	clan = ClanList.Find (arg1, type);
	if (! clan) {
		Ch.SendText ("No such clan.\n\r");
		return;
	}

	if (! strcmp (arg2, "deity")) {
		STRFREE (clan->deity);
		clan->deity = STRALLOC (argument);
		Ch.SendText ("Done.\n\r");
		clan->Save ();
		return;
	}

	if (! strcmp (arg2, "leader")) {
		STRFREE (clan->leader);
		clan->leader = STRALLOC (argument);
		Ch.SendText ("Done.\n\r");
		clan->Save ();
		return;
	}

	if (! strcmp (arg2, "number1")) {
		STRFREE (clan->number1);
		clan->number1 = STRALLOC (argument);
		Ch.SendText ("Done.\n\r");
		clan->Save ();
		return;
	}

	if (! strcmp (arg2, "number2")) {
		STRFREE (clan->number2);
		clan->number2 = STRALLOC (argument);
		Ch.SendText ("Done.\n\r");
		clan->Save ();
		return;
	}

	if (! strcmp (arg2, "board")) {
		clan->board = atoi (argument);
		Ch.SendText ("Done.\n\r");
		clan->Save ();
		return;
	}

	if (! strcmp (arg2, "members")) {
		clan->SetMembers (atoi (argument));
		Ch.SendText ("Done.\n\r");
		clan->Save ();
		return;
	}

	if (! strcmp (arg2, "recall")) {
		clan->recall = atoi (argument);
		Ch.SendText ("Done.\n\r");
		clan->Save ();
		return;
	}

	if (! strcmp (arg2, "storage")) {
		clan->storeroom = atoi (argument);
		Ch.SendText ("Done.\n\r");
		clan->Save ();
		return;
	}

	if (! strcmp (arg2, "obj1")) {
		clan->clanobj1 = atoi (argument);
		Ch.SendText ("Done.\n\r");
		clan->Save ();
		return;
	}

	if (! strcmp (arg2, "obj2")) {
		clan->clanobj2 = atoi (argument);
		Ch.SendText ("Done.\n\r");
		clan->Save ();
		return;
	}

	if (! strcmp (arg2, "obj3")) {
		clan->clanobj3 = atoi (argument);
		Ch.SendText ("Done.\n\r");
		clan->Save ();
		return;
	}

	if (! strcmp (arg2, "guard1")) {
		clan->guard1 = atoi (argument);
		Ch.SendText ("Done.\n\r");
		clan->Save ();
		return;
	}

	if (! strcmp (arg2, "guard2")) {
		clan->guard2 = atoi (argument);
		Ch.SendText ("Done.\n\r");
		clan->Save ();
		return;
	}

	if (Ch.GetTrustLevel () < LEVEL_SUB_IMPLEM) {
		SetclanGuildOrOrder (Ch, "", type);
		return;
	}

	if (! strcmp (arg2, "align")) {
		clan->alignment = atoi (argument);
		Ch.SendText ("Done.\n\r");
		clan->Save ();
		return;
	}

	if (! strcmp (arg2, "class")) {
		clan->m_Class = atoi (argument);
		Ch.SendText ("Done.\n\r");
		clan->Save ();
		return;
	}

	if (! strcmp (arg2, "name")) {
		STRFREE (clan->GetName ());
		clan->SetName (argument);
		Ch.SendText ("Done.\n\r");
		clan->Save ();
		return;
	}

	if (! strcmp (arg2, "filename")) {
		delete clan->GetFilename ();
		clan->SetFilename (argument);
		Ch.SendText ("Done.\n\r");
		clan->Save ();
		ClanList.Write ();
		return;
	}

	if (! strcmp (arg2, "motto")) {
		STRFREE (clan->motto);
		clan->motto = STRALLOC (argument);
		Ch.SendText ("Done.\n\r");
		clan->Save ();
		return;
	}

	if (! strcmp (arg2, "desc")) {
		clan->SetDescription (argument);
		Ch.SendText ("Done.\n\r");
		clan->Save ();
		return;
	}

	if (! stricmp (arg2, "delete")) {
		CString	FName = FileTable.MakeName (SD_CLAN_DIR,
			clan->GetFilename ());
		CString	BName = FileTable.MakeBackupName (FName);
		remove (BName);
		rename (FName, BName);

		ClanList.Remove (clan);
		delete clan;
		ClanList.Write ();
		Ch.SendTextf ("%s %s Deleted.\n\r", tname, arg1);
		return;
	}

	SetclanGuildOrOrder (Ch, "", type);
}


//Load a clan file
BOOL load_clan_file (char *clanfile)
{
	CClanData	*clan;
	FILE		*fp;
	char		*pLine;

	clan = new CClanData;

	BOOL	bFound = FALSE;
	if ((fp = fopen (FileTable.MakeName (SD_CLAN_DIR, clanfile), "r"))) {
		bFound = TRUE;
		for (;;) {
			char	letter;
			char	*word;

			pLine = fread_line (fp);
			letter = *pLine++;

			if (letter == '*')
				continue;

			if (letter != '#') {
				bug ("Load_clan_file: # not found.");
				break;
			}

			word = ParseWord (pLine);
			if (! str_cmp (word, "CLAN")) {
				clan->Read (fp);
				break;
			}
			else if (! str_cmp (word, "END"	))
				break;
			else {
				bug ("Load_clan_file: bad section: %s.", word);
				break;
			}
		}
		fclose (fp);
	}

	if (bFound) {
		CRoomIndexData *storeroom;

		ClanList.AddTail (clan);

		if (clan->storeroom == 0
		  || (storeroom = RoomTable.GetRoom (clan->storeroom)) == NULL) {
			gpDoc->LogString ("Storeroom not found", LOG_BOOT);
			return bFound;
		}

		CString	Fname = FileTable.MakeName (SD_CLAN_DIR, clan->GetFilename ());
		Fname += ".vault";

		if ((fp = fopen (Fname, "r")) != NULL) {
			int			iNest;
			CObjData	*tobj;

			gpDoc->LogString ("Loading clan storage room", LOG_BOOT);
			rset_supermob (storeroom);
			for (iNest = 0; iNest < MAX_NEST; iNest++)
				rgObjNest [iNest] = NULL;

			for (;;) {
				char	letter;
				char	*word;

				pLine = fread_line (fp);
				letter = *pLine++;

				if (letter == '*')
					continue;

				if (letter != '#') {
					bug ("Load_clan_vault: # char not found (%s).",
						clan->GetName ());
					break;
				}

				word = ParseWord (pLine);
				if (! str_cmp (word, "OBJECT"))					// Objects
					fread_obj (supermob, fp, OS_CARRY);
				else if (! str_cmp (word, "END"   ))			// Done
					break;
				else {
					bug ("Load_clan_vault: bad section (%s).",
						clan->GetName ());
					break;
				}
			}

			fclose (fp);
			POSITION	pos = supermob->GetHeadCarryPos ();
			while (tobj = supermob->GetNextCarrying (pos)) {
				obj_from_char (tobj);
				obj_to_room (tobj, storeroom);
			}
			release_supermob ();
		}
		else gpDoc->LogString ("Cannot open clan vault", LOG_BOOT);
	}
	else delete clan;

	return bFound;
}


// Save items in a clan storage room			-Scryn & Thoric
void CClanData::SaveStoreroom (CCharacter *ch)
{
	FILE		*fp;
	short		templvl;

	if (!ch) {
		bug  ("save_clan_storeroom: Null ch pointer!");
		return;
	}

	CString FName = FileTable.MakeName (SD_CLAN_DIR, GetFilename ());
	FName += ".vault";

	if ((fp = fopen (FName, "w")) == NULL)
		bug ("CClanData::SaveStoreroom: fopen: %s", NCCP FName);
	else {
		templvl = ch->GetLevel ();
		ch->SetLevel (LEVEL_HERO);		// make sure EQ doesn't get lost
		if (! ch->GetInRoom ()->IsEmpty ())
			fwrite_obj (ch->GetInRoom ()->GetContentList (), fp,
				0, OS_CARRY);
		fprintf (fp, "#END\n");
		ch->SetLevel (templvl);
		fclose (fp);
	}
}


CCouncilData::~CCouncilData ()
{
	delete filename;
}


CCouncilData *get_council (char *name)
{
	CCouncilData	*council;

	for (council = first_council; council; council = council->GetNext ())
		if (! str_cmp (name, council->name))
			return council;

	return NULL;
}


void write_council_list ()
{
	CCouncilData	*tcouncil;
	FILE			*fpout;

	fpout = fopen (FileTable.GetName (SM_COUNCIL_LIST), "w");
	if (!fpout) {
		bug ("FATAL: cannot open council.lst for writing!\n\r", 0);
		return;
	}	  
	for (tcouncil = first_council; tcouncil; tcouncil = tcouncil->GetNext ())
		fprintf (fpout, "%s\n", tcouncil->filename);
	fprintf (fpout, "$\n");
	fclose (fpout);
}


// Save a council's data to its data file
void save_council (CCouncilData *council)
{
	if (! council) {
		bug ("save_council: null council pointer!");
		return;
	}

	if (! council->filename || council->filename [0] == '\0') {
		bug ("save_council: %s has no filename", council->name);
		return;
	}

	CString	Fname = FileTable.MakeName (SD_COUNCIL_DIR, council->filename);

	fclose (fpReserve);
	FILE	*fp = fopen (Fname, "w");
	if (fp) {
		fprintf (fp, "#COUNCIL\n");
		fprintf (fp, "Name         %s~\n",	council->name);
		fprintf (fp, "Filename     %s~\n",	council->filename);
		fprintf (fp, "Description  %s~\n",	council->description);
		fprintf (fp, "Head         %s~\n",	council->head);
		fprintf (fp, "Members      %d\n",	council->m_Members);
		fprintf (fp, "Board        %d\n",	council->board);
		fprintf (fp, "Meeting      %d\n",	council->meeting);
		fprintf (fp, "Powers       %s~\n",	council->powers);
		fprintf (fp, "End\n\n");
		fprintf (fp, "#END\n");
		fclose (fp);
	}
	else bug ("save_council: Cannot create %s", NCCP Fname);

	fpReserve = fopen (FileTable.GetName (SM_NULL_FILE), "r");
}


// Read in actual council data.
#if defined (KEY)
#undef KEY
#endif

#define KEY(literal,field,value)					\
				if (!str_cmp (word, literal)) {		\
				    field  = value;					\
				    fMatch = TRUE;					\
				    break;							\
				}

void fread_council (CCouncilData *council, FILE *fp)
{
	char	buf [MAX_STRING_LENGTH];
	char	*word, *pLine;
	BOOL	fMatch;

	for (;;) {
		fMatch = FALSE;
		if (! feof (fp)) {
			pLine = fread_line (fp);
			word = ParseWord (pLine);
		}
		else word = "End";

		switch  (UPPER (word [0])) {
		  case '*':
			fMatch = TRUE;
			break;

		  case 'B':
			KEY ("Board",	council->board,		ParseNumber (pLine));
			break;

		  case 'D':
			KEY ("Description",	council->description, ParseString (pLine, fp));
			break;

		  case 'E':
			if (! str_cmp (word, "End")) {
				if (!council->name)
					council->name = STRALLOC ("");
				if (!council->description)
					council->description = STRALLOC ("");
				if (!council->powers)
					council->powers	= STRALLOC ("");
				return;
			}
			break;

		  case 'F':
			KEY ("Filename", council->filename, ParseStringNohash (pLine, fp));
			break;

		  case 'H':
			KEY ("Head", 	council->head, 		ParseString (pLine, fp));
			break;

		  case 'M':
			KEY ("Members",		council->m_Members,	ParseNumber (pLine));
			KEY ("Meeting",   	council->meeting, 	ParseNumber (pLine));
			break;

		  case 'N':
			KEY ("Name",	council->name,		ParseString (pLine, fp));
			break;

		  case 'P':
			KEY ("Powers",	council->powers,	ParseString (pLine, fp));
			break;
		}

		if (! fMatch) {
			sprintf (buf, "Fread_council: no match: %s", word);
			bug (buf);
		}
	}
}


// Load a council file
BOOL load_council_file (char *councilfile)
{
	CCouncilData	*council;
	FILE			*fp;
	char			*pLine;

	council = new CCouncilData;

	BOOL	found = FALSE;
	if ((fp = fopen (FileTable.MakeName (SD_COUNCIL_DIR, councilfile), "r"))){
		found = TRUE;
		for (;;) {
			char	letter;
			char	*word;

			pLine = fread_line (fp);
			letter = *pLine++;

			if (letter == '*')
				continue;

			if (letter != '#') {
				bug ("Load_council_file: # not found.");
				break;
			}

			word = ParseWord (pLine);
			if (! str_cmp (word, "COUNCIL")) {
				fread_council (council, fp);
				break;
			}
			else
				if (! str_cmp (word, "END"))
					break;
			else {
				bug ("Load_council_file: bad section.");
				break;
			}
		}
		fclose (fp);
	}

	if (found)
		LINK (council, first_council, last_council);

	else
		delete council;

	return found;
}


// Load in all the council files.
void load_councils ()
{
	FILE	*fp;
	char	*pFname, *pLine;

	first_council = NULL;
	last_council = NULL;

	gpDoc->LogString ("Loading councils...", LOG_BOOT);

	fclose (fpReserve);
	if (! (fp = fopen (FileTable.GetName (SM_COUNCIL_LIST), "r"))) {
		perror (FileTable.GetName (SM_COUNCIL_LIST));
		ThrowSmaugException (SE_COUNCIL);
	}

	while (! feof (fp)) {
		pLine = fread_line (fp);
		pFname = ParseLine (pLine);
		if (pFname [0] == '$') then break;
		gpDoc->LogString (pFname, LOG_BOOT);

		if (!load_council_file (pFname))
			bug ("Cannot load council file: %s", pFname);
	}
	fclose (fp);
	fpReserve = fopen (FileTable.GetName (SM_NULL_FILE), "r");
}


void do_make (CCharacter *ch, char *argument)
{
    char arg[MAX_INPUT_LENGTH];
    CObjIndexData *pObjIndex;
    CObjData *obj;
    CClanData *clan;
    int level;

    if (ch->IsNpc () || !ch->GetPcData ()->GetClan ())
    {
	ch->SendText ("Huh?\n\r");
	return;
    }

    clan = ch->GetPcData ()->GetClan ();
    
    if (str_cmp (ch->GetName (), clan->leader)
    &&   str_cmp (ch->GetName (), clan->deity)
    &&   (clan->GetType () != CLAN_GUILD
    ||   str_cmp (ch->GetName (), clan->number1)))
    {
	ch->SendText ("Huh?\n\r");
	return;
    }

    argument = one_argument (argument, arg);

    if (arg[0] == '\0')
    {
	ch->SendText ("Make what?\n\r");
	return;
    }

    pObjIndex = OIdxTable.GetObj (clan->clanobj1);
    level = 40;

    if (!pObjIndex || !is_name (arg, pObjIndex->GetName ()))
    {
      pObjIndex = OIdxTable.GetObj (clan->clanobj2);
      level = 45;
    }
    if (!pObjIndex || !is_name (arg, pObjIndex->GetName ()))
    {
      pObjIndex = OIdxTable.GetObj (clan->clanobj3);
      level = 50;
    }

    if (!pObjIndex || !is_name (arg, pObjIndex->GetName ()))
    {
	ch->SendText ("You don't know how to make that.\n\r");
	return;
    }

    obj = create_object (pObjIndex, level);
    obj->SetClanObject ();
    if (obj->CanWear (ITEM_TAKE))
      obj = obj_to_char (obj, ch);
    else
      obj = obj_to_room (obj, ch->GetInRoom ());
    act (AT_MAGIC, "$n makes $p!", ch, obj, NULL, TO_ROOM);
    act (AT_MAGIC, "You make $p!", ch, obj, NULL, TO_CHAR);
    return;
}


void do_induct (CCharacter *ch, char *argument)
{
	char		arg [MAX_INPUT_LENGTH];
	CCharacter	*victim;
	pc_data		&Pc = *ch->GetPcData ();

	if (! &Pc || ch->IsNpc () || ! Pc.GetClan ()) {
		ch->SendText ("Huh?\n\r");
		return;
	}

	CClanData	*pClan = Pc.GetClan ();

	if ((Pc.GetBestowments () && is_name ("induct", Pc.GetBestowments ()))
	  || !str_cmp (ch->GetName (), pClan->deity)
	  || !str_cmp (ch->GetName (), pClan->leader)
	  || !str_cmp (ch->GetName (), pClan->number1)
	  || !str_cmp (ch->GetName (), pClan->number2))
	;
	else {
		ch->SendText ("Huh?\n\r");
		return;
	}

	argument = one_argument (argument, arg);

	if (arg [0] == '\0') {
		ch->SendText ("Induct whom?\n\r");
		return;
	}

	if ((victim = get_char_room (ch, arg)) == NULL) {
		ch->SendText ("That player is not here.\n\r");
		return;
	}

	if (victim->IsNpc ()) {
		ch->SendText ("Not on NPC's.\n\r");
		return;
	}

	if (pClan->GetType () == CLAN_GUILD) {
		if (victim->GetClass () != pClan->m_Class) {
			ch->SendText ("This player's will is not in accordance with "
				"your guild.\n\r");
			return;
		}
	} else {
		if (victim->GetLevel () < 10) {
			ch->SendText ("This player is not worthy of joining yet.\n\r");
			return;
		}

		if (victim->GetLevel () > ch->GetLevel ()) {
			ch->SendText ("This player is too powerful for you to induct.\n\r");
			return;
		}
	}

	if (victim->GetPcData ()->GetClan ()) {
		if (victim->GetPcData ()->GetClan ()->GetType () == CLAN_ORDER) {
			if (victim->GetPcData ()->GetClan () == pClan)
				ch->SendText ("This player already belongs to your order!\n\r");
			else
				ch->SendText ("This player already belongs to an order!\n\r");
			return;
		}
		else if (victim->GetPcData ()->GetClan ()->GetType () == CLAN_GUILD) {
			if (victim->GetPcData ()->GetClan () == pClan)
				ch->SendText ("This player already belongs to your guild!\n\r");
			else
				ch->SendText ("This player already belongs to a guild!\n\r");
			return;
		} else {
			if (victim->GetPcData ()->GetClan () == pClan)
				ch->SendText ("This player already belongs to your clan!\n\r");
			else
				ch->SendText ("This player already belongs to a clan!\n\r");
			return;
		}
	}

	pClan->AddMembers (1);
	if (pClan->GetType () != CLAN_ORDER && pClan->GetType () != CLAN_GUILD)
		victim->SetSpeaks (LanguageTable.GetClan ());

	if (pClan->GetType () != CLAN_NOKILL && pClan->GetType () != CLAN_ORDER
		&& pClan->GetType () != CLAN_GUILD)
			victim->SetPkiller ();

	if (pClan->GetType () == CLAN_GUILD) {
		for (int sn = 0; sn < SkillTable.GetCount (); sn++) {
			if (SkillTable.GetGuild (sn) == pClan->m_Class &&
			  SkillTable.GetName (sn) != NULL) {
				victim->GetPcData ()->learned [sn] =
					SkillTable.GetClassAdept (sn, victim->GetClass ());
				victim->SendTextf ("%s instructs you in the ways of %s.\n\r",
					ch->GetName (), SkillTable.GetName (sn));
			}
		}
	}

	victim->GetPcData ()->SetClan (pClan);
	STRFREE (victim->GetPcData ()->GetClanName ());
	victim->GetPcData ()->SetClanName (QUICKLINK (pClan->GetName ()));

	act (AT_MAGIC, "You induct $N into $t", ch, pClan->GetName (), victim, TO_CHAR);
	act (AT_MAGIC, "$n inducts $N into $t", ch, pClan->GetName (), victim, TO_NOTVICT);
	act (AT_MAGIC, "$n inducts you into $t", ch, pClan->GetName (), victim, TO_VICT);
	save_char_obj (victim);
}


void do_council_induct (CCharacter *ch, char *argument)
{
	char		 arg [MAX_INPUT_LENGTH];
	CCharacter	 *victim;
	CCouncilData *council;

	if (ch->IsNpc () || ! ch->GetPcData ()->council) {
		ch->SendText ("Huh?\n\r");
		return;
	}

	council = ch->GetPcData ()->council;

	if (str_cmp (ch->GetName (), council->head)) {
		ch->SendText ("Huh?\n\r");
		return;
	}

	argument = one_argument (argument, arg);

	if (arg [0] == '\0') {
		ch->SendText ("Induct whom into your council?\n\r");
		return;
	}

	if ((victim = get_char_room (ch, arg)) == NULL) {
		ch->SendText ("That player is not here.\n\r");
		return;
	}

	if (victim->IsNpc ()) {
		ch->SendText ("Not on NPC's.\n\r");
		return;
	}

	if (victim->GetPcData ()->council) {
		ch->SendText ("This player already belongs to a council!\n\r");
		return;
	}

	council->AddMembers (1);
	victim->GetPcData ()->council = council;
	STRFREE (victim->GetPcData ()->GetCouncilName ());
	victim->GetPcData ()->SetCouncilName (QUICKLINK (council->name));
	act (AT_MAGIC, "You induct $N into $t", ch, council->name, victim, TO_CHAR);
	act (AT_MAGIC, "$n inducts $N into $t", ch, council->name, victim, TO_ROOM);
	act (AT_MAGIC, "$n inducts you into $t", ch, council->name, victim, TO_VICT);
	save_char_obj (victim);
	save_council (council);
}


void do_outcast (CCharacter *ch, char *argument)
{
	char		arg [MAX_INPUT_LENGTH];
	char		buf [MAX_STRING_LENGTH];
	CCharacter	*victim;
	pc_data		&Pc = *ch->GetPcData ();

	if (! &Pc || ch->IsNpc () || ! Pc.GetClan ()) {
		ch->SendText ("Huh?\n\r");
		return;
	}

	CClanData	*pClan = Pc.GetClan ();

	if ((Pc.GetBestowments () && is_name ("outcast", Pc.GetBestowments ()))
	  || !str_cmp (ch->GetName (), pClan->deity  )
	  || !str_cmp (ch->GetName (), pClan->leader )
	  || !str_cmp (ch->GetName (), pClan->number1)
	  || !str_cmp (ch->GetName (), pClan->number2))
	  ;
	else {
		ch->SendText ("Huh?\n\r");
		return;
	}


	argument = one_argument (argument, arg);

	if (arg [0] == '\0') {
		ch->SendText ("Outcast whom?\n\r");
		return;
	}

	if ((victim = get_char_room (ch, arg)) == NULL) {
		ch->SendText ("That player is not here.\n\r");
		return;
	}

	if (victim->IsNpc ()) {
		ch->SendText ("Not on NPC's.\n\r");
		return;
	}

	if (victim == ch) {
		if (ch->GetPcData ()->GetClan ()->GetType () == CLAN_ORDER) {
			ch->SendText ("Kick yourself out of your own order?\n\r");
			return;
		}
		else if (ch->GetPcData ()->GetClan ()->GetType () == CLAN_GUILD) {
			ch->SendText ("Kick yourself out of your own guild?\n\r");
			return;
		} else {
			ch->SendText ("Kick yourself out of your own clan?\n\r");
			return;
		}
	}

	if (victim->GetLevel () > ch->GetLevel ()) {
		ch->SendText ("This player is too powerful for you to outcast.\n\r");
		return;
	}

	if (victim->GetPcData ()->GetClan () != ch->GetPcData ()->GetClan ()) {
		if (ch->GetPcData ()->GetClan ()->GetType () == CLAN_ORDER) {
			ch->SendText ("This player does not belong to your order!\n\r");
			return;
		}
		else if (ch->GetPcData ()->GetClan ()->GetType () == CLAN_GUILD) {
			ch->SendText ("This player does not belong to your guild!\n\r");
			return;
		} else {
			ch->SendText ("This player does not belong to your clan!\n\r");
			return;
		}
	}

	if (pClan->GetType () == CLAN_GUILD) {
		for (int sn = 0; sn < SkillTable.GetCount (); sn++)
			if (SkillTable.GetGuild (sn) ==
			  victim->GetPcData ()->GetClan ()->m_Class
			  && SkillTable.GetName (sn) != NULL) {
				victim->GetPcData ()->learned [sn] = 0;
				ch->SendTextf ("You forget the ways of %s.\n\r",
					SkillTable.GetName (sn));
			}
	}

	if (victim->IsSpeaking (LanguageTable.GetClan ()))
		victim->SetSpeaking (LanguageTable.GetCommon ());
	victim->ClrSpeaks (LanguageTable.GetClan ());
	pClan->AddMembers (-1);

	if (!str_cmp (victim->GetName (), ch->GetPcData ()->GetClan ()->number1)){
		STRFREE (ch->GetPcData ()->GetClan ()->number1);
		ch->GetPcData ()->GetClan ()->number1 = STRALLOC ("");
	}
	if (!str_cmp (victim->GetName (), ch->GetPcData ()->GetClan ()->number2)){
		STRFREE (ch->GetPcData ()->GetClan ()->number2);
		ch->GetPcData ()->GetClan ()->number2 = STRALLOC ("");
	}

	victim->GetPcData ()->SetClan (NULL);
	STRFREE (victim->GetPcData ()->GetClanName ());
	victim->GetPcData ()->SetClanName (STRALLOC (""));

	act (AT_MAGIC, "You outcast $N from $t", ch, pClan->GetName (), victim, TO_CHAR);
	act (AT_MAGIC, "$n outcasts $N from $t", ch, pClan->GetName (), victim, TO_ROOM);
	act (AT_MAGIC, "$n outcasts you from $t", ch, pClan->GetName (), victim, TO_VICT);
	if (pClan->GetType () != CLAN_GUILD) {
		sprintf (buf, "%s has been outcast from %s!", victim->GetName (),
			pClan->GetName ());
		echo_to_all (AT_MAGIC, buf, ECHOTAR_ALL);
	}

	save_char_obj (victim);		// clan gets saved when pfile is saved
}


void do_council_outcast (CCharacter *ch, char *argument)
{
	char		 arg[MAX_INPUT_LENGTH];
	CCharacter	 *victim;
	CCouncilData *council;

	if (ch->IsNpc () || ! ch->GetPcData ()->council) {
		ch->SendText ("Huh?\n\r");
		return;
	}

	council = ch->GetPcData ()->council;

	if (str_cmp (ch->GetName (), council->head)) {
		ch->SendText ("Huh?\n\r");
		return;
	}

	argument = one_argument (argument, arg);

	if (arg [0] == '\0') {
		ch->SendText ("Outcast whom from your council?\n\r");
		return;
	}

	if ((victim = get_char_room (ch, arg)) == NULL) {
		ch->SendText ("That player is not here.\n\r");
		return;
	}

	if (victim->IsNpc ()) {
		ch->SendText ("Not on NPC's.\n\r");
		return;
	}

	if (victim == ch) {
		ch->SendText ("Kick yourself out of your own council?\n\r");
		return;
	}

	if (victim->GetPcData ()->council != ch->GetPcData ()->council) {
		ch->SendText ("This player does not belong to your council!\n\r");
		return;
	}

	council->AddMembers (-1);
	victim->GetPcData ()->council = NULL;
	STRFREE (victim->GetPcData ()->GetCouncilName ());
	victim->GetPcData ()->SetCouncilName (STRALLOC (""));
	act (AT_MAGIC, "You outcast $N from $t", ch, council->name, victim, TO_CHAR);
	act (AT_MAGIC, "$n outcasts $N from $t", ch, council->name, victim, TO_ROOM);
	act (AT_MAGIC, "$n outcasts you from $t", ch, council->name, victim, TO_VICT);
	save_char_obj (victim);
	save_council (council);
}


void do_setcouncil (CCharacter *ch, char *argument)
{
	char	arg1 [MAX_INPUT_LENGTH];
	char	arg2 [MAX_INPUT_LENGTH];

	if (ch->IsNpc ()) {
		ch->SendText ("Huh?\n\r");
		return;
	}

	argument = one_argument (argument, arg1);
	argument = one_argument (argument, arg2);

	if (arg1 [0] == '\0') {
		ch->SendText ("Usage: setcouncil <council> <field> <deity|leader"
			"|number1|number2> <player>\n\r");
		ch->SendText ("\n\rField being one of:\n\r");
		ch->SendText (" head members board meeting\n\r"); 
		if (ch->GetTrustLevel () >= LEVEL_GOD)
			ch->SendText (" name filename desc\n\r");
		if (ch->GetTrustLevel () >= LEVEL_SUB_IMPLEM)
			ch->SendText (" powers\n\r");
		return;
	}

	CCouncilData	*council = get_council (arg1);
	if (! council) {
		ch->SendText ("No such council.\n\r");
		return;
	}

	if (! strcmp (arg2, "head")) {
		STRFREE (council->head);
		council->head = STRALLOC (argument);
		ch->SendText ("Done.\n\r");
		save_council (council);
		return;
	}

	if (! strcmp (arg2, "board")) {
		council->board = atoi (argument);
		ch->SendText ("Done.\n\r");
		save_council (council);
		return;
	}

	if (! strcmp (arg2, "members")) {
		council->SetMembers (atoi (argument));
		ch->SendText ("Done.\n\r");
		save_council (council);
		return;
	}

	if (! strcmp (arg2, "meeting")) {
		council->meeting = atoi (argument);
		ch->SendText ("Done.\n\r");
		save_council (council);
		return;
	}

	if (ch->GetTrustLevel () < LEVEL_GOD) {
		do_setcouncil (ch, "");
		return;
	}

	if (! strcmp (arg2, "name")) {
		STRFREE (council->name);
		council->name = STRALLOC (argument);
		ch->SendText ("Done.\n\r");
		save_council (council);
		return;
	}


	if (! strcmp (arg2, "filename")) {
		CString	OldName =
			FileTable.MakeName (SD_COUNCIL_DIR, council->filename);
		CString	NewName = FileTable.MakeName (SD_COUNCIL_DIR, argument);
		if (FileTable.Exists (NewName)) then
			remove (NewName);
		if (FileTable.Exists (OldName))
			rename (OldName, NewName);

		delete council->filename;
		council->filename = str_dup (argument);
		ch->SendText ("Done.\n\r");
		save_council (council);
		write_council_list ();
		return;
	}

	if (! strcmp (arg2, "desc")) {
		STRFREE (council->description);
		council->description = STRALLOC (argument);
		ch->SendText ("Done.\n\r");
		save_council (council);
		return;
	}

	if (ch->GetTrustLevel () < LEVEL_SUB_IMPLEM) {
		do_setcouncil (ch, "");
		return;
	}

	if (! strcmp (arg2, "powers")) {
		STRFREE (council->powers);
		council->powers = STRALLOC (argument);
		ch->SendText ("Done.\n\r");
		save_council (council);
		return;
	}

	do_setcouncil (ch, "");
}


void do_showcouncil (CCharacter *ch, char *argument)
{
	CCouncilData	*council;

	if (ch->IsNpc ()) {
		ch->SendText ("Huh?\n\r");
		return;
	}

	if (argument [0] == '\0') {
		ch->SendText ("Usage: showcouncil <council>\n\r");
		return;
	}

	council = get_council (argument);
	if (! council) {
		ch->SendText ("No such council.\n\r");
		return;
	}

	ch->SendTextf ("Council    : %s\n\rFilename: %s\n\r",
		council->name, council->filename);
	ch->SendTextf ("Description: %s\n\rHead: %s\n\rMembers: %3d\n\r",
		council->description, council->head, council->GetMembers ());
	ch->SendTextf ("Board: %5d\n\rMeeting: %5d\n\rPowers: %s\n\r",
		council->board, council->meeting, council->powers);
}


void do_makecouncil (CCharacter *ch, char *argument)
{
	if (! argument || argument [0] == '\0') {
		ch->SendText ("Usage: makecouncil <council name>\n\r");
		return;
	}

	if (get_council (argument)) {
		ch->SendTextf ("%s Already exists.\n\r", argument);
		return;
	}

	CCouncilData	*co = new CCouncilData;
	CString	Fname;
	Fname.Format ("%s.council", argument);
	co->filename = str_dup (Fname);

	LINK (co, first_council, last_council);
	co->name = STRALLOC (argument);
	co->head = STRALLOC ("");
	co->powers = STRALLOC ("");

	save_council (co);
	write_council_list ();
}


void do_clans (CCharacter *ch, char *argument)
{
	int count = 0;

	// Switched deadly clan mobkills/mobdeaths to pkills -- Blodkai
	set_char_color (AT_BLOOD, ch);
	ch->SendText ("\n\rClan           Deity          Leader            "
		"Pkills\n\r");

	POSITION	pos = ClanList.GetHeadPosition ();
	while (pos) {
		CClanData	&Cl = *ClanList.GetNext (pos);
		if (Cl.GetType () == CLAN_PLAIN) {
			set_char_color (AT_NOTE, ch);
			ch->SendTextf ("%-14s %-14s %-14s", Cl.GetName (), Cl.deity,
				Cl.leader);
			set_char_color (AT_BLOOD, ch);
			ch->SendTextf ("   %7d\n\r", Cl.pkills);
			++count;
		}
	}

	if (! count) {
		set_char_color (AT_BLOOD, ch);
		ch->SendText ("There are no clans currently formed.\n\r");
	}
}


void do_orders (CCharacter *ch, char *argument)
{
	int count = 0;

	// Added displaying of mkills and mdeaths - Brittany
	set_char_color (AT_NOTE, ch);
	ch->SendText ("Order            Deity          Leader        Mkills     Mdeaths\n\r");

	POSITION	pos = ClanList.GetHeadPosition ();
	while (pos) {
		CClanData	&Ord = *ClanList.GetNext (pos);
		if (Ord.GetType () == CLAN_ORDER) {
			ch->SendTextf ("%-16s %-14s %-14s %5d       %5d\n\r",
				Ord.GetName (), Ord.deity, Ord.leader,
				Ord.mkills, Ord.mdeaths);
			count++;
		}
	}

	if (! count)
		ch->SendText ("There are no Orders currently formed.\n\r");
}


void do_councils (CCharacter *ch, char *argument)
{
	CCouncilData	*council;

	if (! first_council) {
		ch->SendText ("There are no councils currently formed.\n\r");
		return;
	}

	set_char_color (AT_NOTE, ch);
	ch->SendText ("Name                  Head\n\r");
	for (council = first_council; council; council = council->GetNext ())
		ch->SendTextf ("%-21s %-14s\n\r", council->name, council->head);
}                                                                           


void do_guilds (CCharacter *ch, char *argument)
{
	int count = 0;

	// Added guild mobkills/mobdeaths -- Blodkai
	set_char_color (AT_NOTE, ch);
	ch->SendText ("\n\rGuild                  Leader             Mkills      Mdeaths\n\r");

	POSITION	pos = ClanList.GetHeadPosition ();
	while (pos) {
		CClanData	&Gui = *ClanList.GetNext (pos);
		if (Gui.GetType () == CLAN_GUILD) {
			set_char_color (AT_YELLOW, ch);
			ch->SendTextf ("%-20s   %-14s     %-6d       %6d\n\r",
				Gui.GetName (), Gui.leader, Gui.mkills, Gui.mdeaths);
			++count;
		}
	}

	set_char_color (AT_NOTE, ch);
	if (! count)
		ch->SendText ("There are no Guilds currently formed.\n\r");
	else
		ch->SendTextf ("%d guilds found.\n\r", count);
}                                                                           


void do_shove (CCharacter *ch, char *argument)
{
	char		arg [MAX_INPUT_LENGTH];
	char		arg2 [MAX_INPUT_LENGTH];
	int			exit_dir;
	CExitData	*pexit;
	CCharacter	*victim;
	BOOL		nogo;
	CRoomIndexData	*to_room;    

	argument = one_argument (argument, arg);
	argument = one_argument (argument, arg2);

	if (ch->IsNpc () || ! ch->IsPkiller ()) {
		ch->SendText ("Only deadly characters can shove.\n\r");
		return;
	}

	if (arg [0] == '\0') {
		ch->SendText ("Shove whom?\n\r");
		return;
	}

	if ((victim = get_char_room (ch, arg)) == NULL) {
		ch->SendText ("They aren't here.\n\r");
		return;
	}

	if (victim == ch) {
		ch->SendText ("You shove yourself around, to no avail.\n\r");
		return;
	}

	if (victim->IsNpc () || ! victim->IsPkiller ()) {
		ch->SendText ("You can only shove deadly characters.\n\r");
		return;
	}

	if (ch->GetLevel () - victim->GetLevel () > 5 
	  || victim->GetLevel () - ch->GetLevel () > 5) {
		ch->SendText ("There is too great an experience difference for "
			"you to even bother.\n\r");
		return;
	}

	if ((victim->GetPosition ()) != POS_STANDING) {
		act (AT_PLAIN, "$N isn't standing up.", ch, NULL, victim, TO_CHAR);
		return;
	}

	if (arg2 [0] == '\0') {
		ch->SendText ("Shove them in which direction?\n\r");
		return;
	}

	exit_dir = get_dir (arg2);
	if (victim->GetInRoom ()->IsSafe ()
	  && get_timer (victim, TIMER_SHOVEDRAG) <= 0) {
		ch->SendText ("That character cannot be shoved right now.\n\r");
		return;
	}

	victim->SetPosition (POS_SHOVE);
	nogo = FALSE;
	if ((pexit = get_exit (ch->GetInRoom (), exit_dir)) == NULL)
		nogo = TRUE;
	else if (pexit->IsClosed () && (! victim->CanPass ()
		|| pexit->IsNoPass ()))
			nogo = TRUE;

	if (nogo) {
		ch->SendText ("There's no exit in that direction.\n\r");
		victim->SetPosition (POS_STANDING);
		return;
	}

	to_room = pexit->GetToRoom ();
	if (to_room->IsDeathRoom ()) {
		ch->SendText ("You cannot shove someone into a death trap.\n\r");
		victim->SetPosition (POS_STANDING);
		return;
	}

	if (ch->GetInRoom ()->GetArea () != to_room->GetArea ()
	  && !in_hard_range (victim, to_room->GetArea ())) {
		ch->SendText ("That character cannot enter that area.\n\r");
		victim->SetPosition (POS_STANDING);
		return;
	}

	// Check for class, assign percentage based on that.
	int	chance = ClassTable.GetShoveDragPercent (ch->GetClass ());

	// Add 3 points to chance for every str point above 15, subtract for 
	// below 15
	chance += ((ch->GetCurrentStrength () - 15) * 3);

	chance += (ch->GetLevel () - victim->GetLevel ());

	chance += RaceTable.GetShoveDragModifier (ch->GetRace ());

	if (chance < number_percent ()) {
		ch->SendText ("You failed.\n\r");
		victim->SetPosition (POS_STANDING);
		return;
	}

	act (AT_ACTION, "You shove $M.", ch, NULL, victim, TO_CHAR);
	act (AT_ACTION, "$n shoves you.", ch, NULL, victim, TO_VICT);
	move_char (victim, get_exit (ch->GetInRoom (),exit_dir), 0);

	if (! char_died (victim))
		victim->SetPosition (POS_STANDING);

	WAIT_STATE (ch, 12);
	// Remove protection from shove/drag if char shoves -- Blodkai
	if (ch->GetInRoom ()->IsSafe ()   
		&& get_timer (ch, TIMER_SHOVEDRAG) <= 0)
			add_timer (ch, TIMER_SHOVEDRAG, 10, NULL, 0);
}


void do_drag (CCharacter *ch, char *argument)
{
	char		arg [MAX_INPUT_LENGTH];
	char		arg2 [MAX_INPUT_LENGTH];
	int			exit_dir;
	CCharacter	*victim;
	CExitData	*pexit;
	CRoomIndexData	*to_room;
	BOOL		nogo;

	argument = one_argument (argument, arg);
	argument = one_argument (argument, arg2);

	if (ch->IsNpc () || ! ch->IsPkiller ()) {
		ch->SendText ("Only deadly characters can drag.\n\r");
		return;
	}

	if (arg [0] == '\0') {
		ch->SendText ("Drag whom?\n\r");
		return;
	}

	if ((victim = get_char_room (ch, arg)) == NULL) {
		ch->SendText ("They aren't here.\n\r");
		return;
	}

	if (victim == ch) {
		ch->SendText ("You take yourself by the scruff of your neck, but"
			" go nowhere.\n\r");
		return; 
	}

	if (victim->IsNpc () || ! victim->IsPkiller ()) {
		ch->SendText ("You can only drag deadly characters.\n\r");
		return;
	}

	if (victim->GetFightData ()) {
		ch->SendText ("You try, but can't get close enough.\n\r");
		return;
	}

	if (arg2 [0] == '\0') {
		ch->SendText ("Drag them in which direction?\n\r");
		return;
	}

	if (ch->GetLevel () - victim->GetLevel () > 5
	  || victim->GetLevel () - ch->GetLevel () > 5) {
		ch->SendText ("There is too great an experience difference for you to even bother.\n\r");
		return;
	}

	exit_dir = get_dir (arg2);

	if (victim->GetInRoom ()->IsSafe ()
	  && get_timer (victim, TIMER_SHOVEDRAG) <= 0) {
		ch->SendText ("That character cannot be dragged right now.\n\r");
		return;
	}

	nogo = FALSE;
	if ((pexit = get_exit (ch->GetInRoom (), exit_dir)) == NULL)
		nogo = TRUE;
	else
		if (pexit->IsClosed () &&  (! victim->CanPass ()
			|| pexit->IsNoPass ()))
				nogo = TRUE;
	if (nogo) {
		ch->SendText ("There's no exit in that direction.\n\r");
		return;
	}

	to_room = pexit->GetToRoom ();
	if (to_room->IsDeathRoom ()) {
		ch->SendText ("You cannot drag someone into a death trap.\n\r");
		return;
	}

	if (ch->GetInRoom ()->GetArea () != to_room->GetArea ()
	  && !in_hard_range (victim, to_room->GetArea ())) {
		ch->SendText ("That character cannot enter that area.\n\r");
		victim->SetPosition (POS_STANDING);
		return;
	}

	// Check for class, assign percentage based on that.
	int chance = ClassTable.GetShoveDragPercent (ch->GetClass ());

	// Add 3 points to chance for every str point above 15, subtract for 
	// below 15
	chance += ((ch->GetCurrentStrength () - 15) * 3);

	chance += (ch->GetLevel () - victim->GetLevel ());

	chance += RaceTable.GetShoveDragModifier (ch->GetRace ());

	// sprintf (buf, "Drag percentage of %s = %d", ch->GetName (), chance);
	// act (AT_ACTION, buf, ch, NULL, NULL, TO_ROOM);

	if (chance < number_percent ()) {
		ch->SendText ("You failed.\n\r");
		victim->SetPosition (POS_STANDING);
		return;
	}

	if (victim->GetPosition () < POS_STANDING) {
		short	temp = victim->GetPosition ();
		victim->SetPosition (POS_DRAG);
		act (AT_ACTION, "You drag $M into the next room.", ch, NULL, victim, TO_CHAR); 
		act (AT_ACTION, "$n grabs your hair and drags you.", ch, NULL, victim, TO_VICT); 
		move_char (victim, get_exit (ch->GetInRoom (),exit_dir), 0);
		if (!char_died (victim))
			victim->SetPosition (temp);
		// Move ch to the room too.. they are doing dragging - Scryn
		move_char (ch, get_exit (ch->GetInRoom (),exit_dir), 0);
		WAIT_STATE (ch, 12);
		return;
	}
	ch->SendText ("You cannot do that to someone who is standing.\n\r");
}



void CClanList::Write ()
{
	FILE	*fp;

	CString	Fname = FileTable.GetName (SM_CLAN_LIST);
	if (! (fp = fopen (Fname, "w"))) {
		bug ("ClanList::Write: cannot open %s for writing!\n\r", NCCP Fname);
		return;
	}
	
	POSITION	pos = GetHeadPosition ();
	while (pos)
		fprintf (fp, "%s\n", GetNext (pos)->GetFilename ());

	fprintf (fp, "$\n");
	fclose (fp);
}


char* CClanList::GetTypeName (ClanTypes type)
{
	static char	*CTnames [] = { "Clan", "VAMPIRE", "WARRIOR", "DRUID",
				  "MAGE", "CELTIC", "THIEF", "CLERIC",
				  "UNDEAD", "CHAOTIC", "NEUTRAL", "LAWFUL",
				  "NOKILL", "Order", "Guild", "ALL" };

	return CTnames [type];
}


// Get pointer to clan structure from clan name & type.
CClanData *CClanList::Find (const char *name, ClanTypes type)
{
	POSITION	pos = ClanList.GetHeadPosition ();
	while (pos) {
		CClanData	*clan = ClanList.GetNext (pos);
		if ((type == CLAN_ALL || clan->GetType () == type)
			&& ! stricmp (clan->GetName (), name))
				return clan;
	}

	return NULL;
}


void CClanList::Remove (CClanData* clan)
{
	POSITION	pos = CPtrList::Find (clan);

	if (pos)
		RemoveAt (pos);
}


void CClanList::RemoveAll ()
{
	while (! IsEmpty ())
		delete (CClanData*) RemoveTail ();

	CPtrList::RemoveAll ();
}