roh/conf.old/area/
roh/config/code/python/
roh/config/game/area/
roh/config/game/signs/
roh/help/dmhelp/
roh/help/help/
roh/log/
roh/log/staff/
roh/monsters/ocean/
roh/objects/misc/
roh/objects/ocean/
roh/player/
roh/rooms/area/1/
roh/rooms/misc/
roh/rooms/ocean/
roh/src-2.47e/
/*
 * guilds.cpp
 *	 Player run guilds.
 *   ____            _
 *  |  _ \ ___  __ _| |_ __ ___  ___
 *  | |_) / _ \/ _` | | '_ ` _ \/ __|
 *  |  _ <  __/ (_| | | | | | | \__ \
 *  |_| \_\___|\__,_|_|_| |_| |_|___/
 *
 * Permission to use, modify and distribute ics granted via the
 *  Creative Commons - Attribution - Non Commercial - Share Alike 3.0 License
 *    http://creativecommons.org/licenses/by-nc-sa/3.0/
 *
 * 	Copyright (C) 2007-2012 Jason Mitchell, Randi Mitchell
 * 	   Contributions by Tim Callahan, Jonathan Hseu
 *  Based on Mordor (C) Brooke Paul, Brett J. Vickers, John P. Freeman
 *
 */
#include "mud.h"
#include "commands.h"
#include "move.h"
#include "guilds.h"
#include "bank.h"
#include "property.h"
#include "dm.h"
#include "web.h"
#include <fcntl.h>

//*********************************************************************
//						Guild
//*********************************************************************

Guild::Guild() {
	name = "";
	leader = "";
	num = 0;
	level = numMembers = pkillsIn = pkillsWon = 0;
	points = 0;
}

//*********************************************************************
//						getName
//*********************************************************************

bstring Guild::getName() const { return(name); }

//*********************************************************************
//						getNum
//*********************************************************************

unsigned short Guild::getNum() const { return(num); }

//*********************************************************************
//						getLeader
//*********************************************************************

bstring Guild::getLeader() const { return(leader); }

//*********************************************************************
//						getLevel
//*********************************************************************

long Guild::getLevel() const { return(level); }

//*********************************************************************
//						getNumMembers
//*********************************************************************

int Guild::getNumMembers() const { return(numMembers); }

//*********************************************************************
//						getPkillsIn
//*********************************************************************

long Guild::getPkillsIn() const { return(pkillsIn); }

//*********************************************************************
//						getPkillsWon
//*********************************************************************

long Guild::getPkillsWon() const { return(pkillsWon); }

//*********************************************************************
//						getPoints
//*********************************************************************

long Guild::getPoints() const { return(points); }

//*********************************************************************
//						setName
//*********************************************************************

void Guild::setName(bstring n) { name = n; }

//*********************************************************************
//						setNum
//*********************************************************************

void Guild::setNum(unsigned short n) { num = n; }

//*********************************************************************
//						setLeader
//*********************************************************************

void Guild::setLeader(bstring l) { leader = l; }

//*********************************************************************
//						setLevel
//*********************************************************************

void Guild::setLevel(long l) { level = l; }

//*********************************************************************
//						setNumMembers
//*********************************************************************

void Guild::setNumMembers(int n) { numMembers = n; }

//*********************************************************************
//						setPkillsIn
//*********************************************************************

void Guild::setPkillsIn(long pk) { pkillsIn = pk; }

//*********************************************************************
//						setPkillsWon
//*********************************************************************

void Guild::setPkillsWon(long pk) { pkillsWon = pk; }

//*********************************************************************
//						setPoints
//*********************************************************************

void Guild::setPoints(long p) { points = p; }

//*********************************************************************
//						incLevel
//*********************************************************************

void Guild::incLevel(int l) { level += l; }

//*********************************************************************
//						incNumMembers
//*********************************************************************

void Guild::incNumMembers(int n) { numMembers += n; }

//*********************************************************************
//						incPkillsIn
//*********************************************************************

void Guild::incPkillsIn(long pk) { pkillsIn += pk; }

//*********************************************************************
//						incPkillsWon
//*********************************************************************

void Guild::incPkillsWon(long pk) { pkillsWon += pk; }

//*********************************************************************
//						guildhallLocations
//*********************************************************************
// Calling function must provide fmt with 2 %s's. Example:
// "Your guildhall is located at %s in the city of %s.\n"

void Guild::guildhallLocations(const Player* player, const char* fmt) const {
	std::list<Property*>::const_iterator it;

	for(it = gConfig->properties.begin() ; it !=  gConfig->properties.end() ; it++) {
		if((*it)->getType() == PROP_GUILDHALL && (*it)->getGuild() == num) {
			player->print(fmt, (*it)->getLocation().c_str(),
				gConfig->catRefName((*it)->getArea()).c_str());
		}
	}
}

//*********************************************************************
//						GuildCreation
//*********************************************************************

GuildCreation::GuildCreation() {
	name = "";
	leader = leaderIp = "";
	status = numSupporters = 0;
}


// Prototypes

void printGuildSyntax(Player* player) {
	player->printColor("Syntax: guild ^e<^xlist^e>\n");
	player->printColor("              ^e<^xfound^e>^x ^e<^cguild name^e>\n");
	if(gConfig->getWebserver() != "") {
		player->printColor("              ^e<^xforum^e>^x :: set your account to guildmaster on the forum\n");
		player->printColor("                      -create :: create a guild and private board on the website\n");
	}
	player->printColor("              ^e<^xcancel^e>\n");
	player->printColor("              ^e<^xsupport^e>^x ^e<^cguild name^e>\n");
	player->printColor("              ^e<^xinvite^e>^x ^e<^cplayer name^e>\n");
	player->printColor("              ^e<^xremove^e>^x ^e<^cplayer name^e>\n");
	player->printColor("              ^e<^xabdicate^e>^x ^e<^cplayer name^e>\n");
	player->printColor("              ^e<^xaccept^e>\n");
	player->printColor("              ^e<^xreject^e>\n");
	player->printColor("              ^e<^xpromote^e>^x ^e<^cplayer name^e>^x ^e[^crank^e]\n");
	player->printColor("              ^e<^xdemote^e>^x ^e<^cplayer name^e>^x ^e[^crank^e]\n");
	player->printColor("              ^e<^xmembers^e>\n");
	player->printColor("              ^e<^xhall^e>\n");
}


//"              <disband>\n";
// Guild Ranks
//			Non Officer		Officer
//			4,  5,  6,		7,  8,  9     Invite flags
//			12, 13, 14,		17, 18, 19    Actual status

const int	GUILD_NONE = 0,
			GUILD_INVITED = 1,
			GUILD_INVITED_OFFICER = 5,
			GUILD_INVITED_BANKER = 6,

			GUILD_PEON = 11,
			GUILD_OFFICER = 15,
			GUILD_BANKER = 16,
			GUILD_MASTER = 20;

// What happened -- Used in adjusting guild level
const int   GUILD_JOIN = 0,
			GUILD_REMOVE = 1,
			GUILD_LEVEL = 2,
			GUILD_DIE = 3;

// Guild Creation Status variables
const int	GUILD_NEEDS_SUPPORT = 1,
			GUILD_AWAITING_APPROVAL = 2;

// level requirements
const int	GUILD_FOUND_LEVEL = 13,
			GUILD_SUPPORT_LEVEL = 10,
			GUILD_JOIN_LEVEL = 7;


//********************************************************************
//						isGuildKill
//********************************************************************

bool Player::isGuildKill(const Player *killer) const {
	// Dueling guild members don't count
	if(induel(killer, this))
		return(false);

	// Staff members don't count
	if(killer->isStaff() || isStaff())
		return(false);

	// Validate the guild: are they both in one?
	if(!killer->getGuild() || !getGuild())
		return(false);
	// They've reached the lowest level? (ie, skip invited but unconfirmed)
	if(killer->getGuildRank() < GUILD_PEON || getGuildRank() < GUILD_PEON)
		return(false);

	// If they've de-leveled past the join level, they don't count for guild pkilling
	if(killer->getLevel() < GUILD_JOIN_LEVEL || getLevel() < GUILD_JOIN_LEVEL)
		return(false);

	return(true);
}

//*********************************************************************
//						cmdGuild
//*********************************************************************
// Player command used to do various guild functions

int cmdGuild(Player* player, cmd* cmnd) {
	//Creature* target = NULL;
	int		len=0;
	//int len,i=0,j=0;
	//guildCreationPtr newGuildCreation;

	if(cmnd->num < 2) {
		printGuildSyntax(player);
		return(0);
	}

	len = strlen(cmnd->str[1]);

	// Found/Create a new guild
	if(	!strncmp(cmnd->str[1], "found", len) ||
		!strncmp(cmnd->str[1], "create", len)
	) {
		Guild::create(player, cmnd);
	}
	// Cancel the creation of a guild
	else if(!strncmp(cmnd->str[1], "cancel", len)) Guild::cancel(player, cmnd);
	// Create a forum for the guild
	else if(!strncmp(cmnd->str[1], "forum", len)) Guild::forum(player, cmnd);
	// Support the creation of a guild
	else if(!strncmp(cmnd->str[1], "support", len)) Guild::support(player, cmnd);
	// Invite someone into your guild
	else if(!strncmp(cmnd->str[1], "invite", len)) Guild::invite(player, cmnd);
	// Transfer leadership of the guild to someone else
	else if(!strncmp(cmnd->str[1], "abdicate", len)) Guild::abdicate(player, cmnd);
	// Remove someone from your guild
	else if(!strncmp(cmnd->str[1], "remove", len) ||
			!strncmp(cmnd->str[1], "dismiss", len)
	) {
		Guild::remove(player, cmnd);
	}
	// Accept an offer to join a guild
	else if(!strncmp(cmnd->str[1], "join", len) ||
			!strncmp(cmnd->str[1], "accept", len)
	) {
		Guild::join(player, cmnd);
	}
	// Reject someone's offer to join a guild
	else if(!strncmp(cmnd->str[1], "reject", len))	Guild::reject(player, cmnd);
	else if(!strcmp(cmnd->str[1], "disband")) Guild::disband(player, cmnd);
	// Promote someone
	else if(!strncmp(cmnd->str[1], "promote", len)) Guild::promote(player, cmnd);
	// Demote someone
	else if(!strncmp(cmnd->str[1], "demote", len)) Guild::demote(player, cmnd);
	// List current guilds
	else if(!strncmp(cmnd->str[1], "list", len)) Guild::list(player, cmnd);
	else if(!strncmp(cmnd->str[1], "members", len)) Guild::viewMembers(player, cmnd);

	// Guild Bank Stuff
	else if(!strncmp(cmnd->str[1], "balance", len)) Bank::balance(player, true);
	else if(!strncmp(cmnd->str[1], "deposit", len)) Bank::deposit(player, cmnd, true);
	else if(!strncmp(cmnd->str[1], "withdraw", len)) Bank::withdraw(player, cmnd, true);
	else if(!strncmp(cmnd->str[1], "transfer", len)) Bank::transfer(player, cmnd, true);
	else if(!strncmp(cmnd->str[1], "statement", len)) Bank::statement(player, true);
	else if(!strncmp(cmnd->str[1], "deletestatement", len)) Bank::deleteStatement(player, true);

	else if(!strncmp(cmnd->str[1], "hall", len)) Property::manage(player, cmnd, PROP_GUILDHALL, 2);
	else
		printGuildSyntax(player);

	return(0);
}


//*********************************************************************
//						create
//*********************************************************************

void Guild::create(Player* player, cmd* cmnd) {
	int len,i=0,j=0, a=0;
	GuildCreation* newGuildCreation;
	char guildName[41];

	if(player->getLevel() < GUILD_FOUND_LEVEL && !player->isDm()) {
		player->print("You must be level %d to found a guild.\n", GUILD_FOUND_LEVEL);
		return;
	}

	if(player->getGuild() > 0) {
		player->print("You may not create a guild because you already belong to one.\n");
		return;
	}

	// TODO: Check the awaiting approval list to see if they are supporting, or have a guild
	// on the approval list
	if(player->flagIsSet(P_CREATING_GUILD)) {
		player->print("You may only create one guild at a time.\n");
		return;
	}

	if(cmnd->num < 3) {
		printGuildSyntax(player);
		return;
	}

	len = cmnd->fullstr.length();

	// Kill the first 2 spaces
	while(i < len) {
		if(cmnd->fullstr[i] == ' ' && cmnd->fullstr[i+1] != ' ')
			j++;
		if(j==2)
			break;
		i++;
	}

	len = strlen(&cmnd->fullstr[i+1]);
	if(!len) {
		player->print("What would you like to call your guild?\n");
		return;
	}
	if(len > 40) {
		player->print("The guild name is too long.\n");
		return;
	}

	for(a=0;a<len;a++) {
		if(!isalpha(cmnd->fullstr[i+1+a]) && cmnd->fullstr[i+1+a] != ' ') {
			player->print("Name error: Characters other than letters are illegal.\n");
			player->print("Please attempt creation with a different name.\n");
			return;
		}
	}

	strcpy(guildName, &cmnd->fullstr[i+1]);
	if(gConfig->guildExists(guildName)) {
		player->print("A guild with that name already exists or is being considered for creation.\nPlease choose a different guild name.\n");
		return;
	}

	//	newGuild = gConfig->numGuilds + 1;
	//	if(newGuild >= gConfig->maxGuilds)
	//		expandGuildArray();

	newGuildCreation = new GuildCreation;
	newGuildCreation->name = guildName;
	newGuildCreation->leader = player->getName();
	newGuildCreation->leaderIp = player->getSock()->getIp();
	newGuildCreation->status = GUILD_NEEDS_SUPPORT;
	newGuildCreation->numSupporters = 0;

	gConfig->addGuildCreation(newGuildCreation);
	player->setFlag(P_CREATING_GUILD);
	player->printColor("%sYou attempting to create a guild with the name of '%s'.\n", player->customColorize("*CC:GUILD*").c_str(), guildName);
	player->print("Go find %d people to support your guild now.\n", SUPPORT_REQUIRED);
	broadcast(isCt, "^y%s is attempting to create the guild '%s'.", player->getCName(), guildName);
	gConfig->saveGuilds();
}

//*********************************************************************
//						cancel
//*********************************************************************

void Guild::cancel(Player* player, cmd* cmnd) {
	if(!player->flagIsSet(P_CREATING_GUILD)) {
		player->print("You aren't currently creating any guilds!\n");
		return;
	}
	player->clearFlag(P_CREATING_GUILD);
	bstring guildName = gConfig->removeGuildCreation(player->getName());

	if(guildName != "") {
		player->print("You remove your bid to create '%s'.\n", guildName.c_str());
		return;
	}

	player->print("You aren't creating any guilds!\n");
}

//*********************************************************************
//						forum
//*********************************************************************
// calls the webserver - no work is done here (besides parsing)

void Guild::forum(Player* player, cmd* cmnd) {
	if(!player->getGuild() || player->getGuildRank() != GUILD_MASTER) {
		player->print("You are not a guildmaster.\n");
		return;
	}

	Guild* guild = gConfig->getGuild(player->getGuild());
	if(!guild || strstr(guild->name.c_str(), "&")) {
		player->print("Invalid guild!\n");
		return;
	}
	if(gConfig->getWebserver() == "") {
		player->print("The mud currently does not have a webserver configured.\n");
		return;
	}

	if(player->getForum() == "") {
		player->print("Your player must be associated with a forum account to update or create a guild forum.\n");
		return;
	}

	bstring action = cmnd->str[2];
	std::ostringstream url;
	url << "mud.php?mud_id=" << guild->getNum() << "&char=" << player->getName() << "&type=";

	if(action == "-create") {
		player->printColor("Attempting to create guild forum with you as guildmaster.\n");
		url << "guildCreate&guildName=" << guild->name;
	} else {
		player->printColor("Attempting to update guild forum with you as guildmaster.\n");
		url << "guildAbdicate";
	}

	callWebserver(url.str());
}

//*********************************************************************
//						support
//*********************************************************************

void Guild::support(Player* player, cmd* cmnd) {
	GuildCreation *toSupport=0;
	char	guildName[41];
	int		len=0, i=0, j=0;

	if(player->getLevel() < GUILD_SUPPORT_LEVEL && !player->isDm()) {
		player->print("You must be level %d to support a guild!\n", GUILD_SUPPORT_LEVEL);
		return;
	}

	if(player->getGuild() > 0) {
		player->print("You may not support a guild because you already belong to one.\n");
		return;
	}
	if(player->flagIsSet(P_CREATING_GUILD)) {
		player->print("You may only support one guild at a time.\n");
		return;
	}

	if(cmnd->num < 3) {
		printGuildSyntax(player);
		return;
	}

	len = cmnd->fullstr.length();

	// Kill the first 2 spaces
	while(i < len) {
		if(cmnd->fullstr[i] == ' ' && cmnd->fullstr[i+1] != ' ')
			j++;
		if(j==2)
			break;
		i++;
	}

	len = strlen(&cmnd->fullstr[i+1]);
	if(!len) {
		player->print("Which guild would you like to support?\n");
		return;
	}
	if(len>40)
		cmnd->fullstr[40] = '\0';

	strcpy(guildName, &cmnd->fullstr[i+1]);
	toSupport = gConfig->findGuildCreation(guildName);
	if(toSupport == NULL) {
		player->print("'%s' is not currently up for creation.\n", guildName);
		return;
	}
	if(toSupport->status != GUILD_NEEDS_SUPPORT) {
		player->print("'%s' is not currently in need of support.\n", guildName);
		return;
	}


	if(!player->flagIsSet(P_PTESTER)) {
		// check the address
		bool sameIp = (player->getSock()->getIp() == toSupport->leaderIp);

		if(!sameIp) {
			std::map<bstring, bstring>::iterator sIt;
			for(sIt = toSupport->supporters.begin() ; sIt != toSupport->supporters.end() ; sIt++) {
				if((*sIt).second == player->getSock()->getIp()) {
					sameIp = true;
					break;
				}
			}
		}
		if(sameIp) {
			player->print("Someone from your IP address is already supporting this guild.\n");
			player->print("Remember, do not use alternate characters to support a guild.\n");
			return;
		}
	}

	player->setFlag(P_CREATING_GUILD);

	player->print("You now supporting the creation of the guild '%s'.\n", guildName);
	broadcast(isCt, "^y%s is supporting the guild '%s'.", player->getCName(), guildName);
	toSupport->addSupporter(player);

	if(toSupport->numSupporters >= SUPPORT_REQUIRED) {
		Player* leader=0;

		toSupport->status = GUILD_AWAITING_APPROVAL;
		// We now have enough players to seek staff approval
		player->print("There are now enough people supporting the guild, it has been submitted for staff approval.\n");
		leader = gServer->findPlayer(toSupport->leader.c_str());
		if(leader)
			leader->printColor("%sThere are now enough people supporting your guild, it has been submitted for staff approval.\n", leader->customColorize("*CC:GUILD*").c_str());
		broadcast(isCt, "^yThe guild '%s' is in need of staff approval.", guildName);
	}

	gConfig->saveGuilds();
}

//*********************************************************************
//						invite
//*********************************************************************

void Guild::invite(Player* player, cmd* cmnd) {
	Player	*target=0;

	if(!player->getGuild() || player->getGuildRank() < GUILD_OFFICER) {
		player->print("You are not an officer in a guild.\n");
		return;
	}

	if(cmnd->num < 3) {
		player->print("Invite who into your guild?\n");
		return;
	}

	lowercize(cmnd->str[2], 1);
	target = gServer->findPlayer(cmnd->str[2]);

	if(!target || !player->canSee(target)) {
		player->print("%s is not on.\n", cmnd->str[2]);
		return;
	}

	if(Move::tooFarAway(player, target, "invite into your guild"))
		return;

	if(target->getLevel() < GUILD_JOIN_LEVEL) {
		player->print("%s does not meet the minimum required level of %d to join a guild!\n",
			target->getCName(), GUILD_JOIN_LEVEL);
		return;
	}

	if(target->getGuildRank() >= GUILD_INVITED && target->getGuildRank() < GUILD_PEON) {
		player->print("%s is currently considering joining a guild already.\n", target->getCName());
		return;
	}

	if(target->getGuild()) {
		player->print("%s is already in a guild.\n", target->getCName());
		return;
	}

	if(target->isStaff()) {
		player->print("You cannot invite staff members to join a guild.\n");
		return;
	}

	// Set this initially, change it if needed
	target->setGuildRank(GUILD_INVITED);
	target->setGuild(player->getGuild());

	if(player->getGuildRank() == GUILD_MASTER) {
		if(!strncmp(cmnd->str[3], "officer", strlen(cmnd->str[3])) && cmnd->num == 4) {
			player->print("You invite %s to join your guild as an officer.\n", target->getCName());
			target->print("You have been invited to join '%s' as an officer by %s.\n", getGuildName(player->getGuild()), player->getCName());
			target->setGuildRank(GUILD_INVITED_OFFICER);
		} else if(!strncmp(cmnd->str[3], "banker", strlen(cmnd->str[3])) && cmnd->num == 4) {
			player->print("You invite %s to join your guild as a banker.\n", target->getCName());
			target->print("You have been invited to join '%s' as a banker by %s.\n", getGuildName(player->getGuild()), player->getCName());
			target->setGuildRank(GUILD_INVITED_BANKER);
		} else {
			player->print("You invite %s to join your guild as a normal member.\n", target->getCName());
			target->print("You have been invited to join '%s' by %s.\n", getGuildName(player->getGuild()), player->getCName());
			target->setGuildRank(GUILD_INVITED);
		}
	} else {
		player->print("You invite %s to join your guild as a normal member.\n", target->getCName());
		target->print("You have been invited to join '%s' by %s.\n", getGuildName(player->getGuild()), player->getCName());
		target->setGuildRank(GUILD_INVITED);
	}

	target->printColor("To join type ^yguild accept^x.\n");
}

//*********************************************************************
//						shopStaysWithGuild
//*********************************************************************

bool shopStaysWithGuild(const UniqueRoom* shop) {
	return(!shop->exits.empty() && shop->exits.front()->target.room.isArea("guild"));
}

//*********************************************************************
//						remove
//*********************************************************************

void shopRemoveGuild(Property *p, Player* player, UniqueRoom* shop, UniqueRoom* storage);

void Guild::remove(Player* player, cmd* cmnd) {
	Player	*target=0;
	Property* p=0;
	int guildId = player->getGuild();

	if((!player->getGuild() || player->getGuildRank() < GUILD_OFFICER) && cmnd->num >= 3) {
		player->print("You are not an officer. You can't do that.\n");
		return;
	}
	if(!player->getGuild()) {
		player->print("You aren't in a guild!\n");
		return;
	}

	if(cmnd->num < 3) { // Remove yourself
		if(player->getGuildRank() != GUILD_MASTER) {

			if(!canRemovePlyFromGuild(player)) {
				player->print("Guilds cannot drop below 3 players, the guild must be disbanded.\n");
				return;
			}
			updateGuild(player, GUILD_REMOVE);
			player->print("You remove yourself from your guild (%s).\n", getGuildName(player->getGuild()));
			
			player->setGuild(0);
			broadcastGuild(guildId, 1, "%s has removed %sself from your guild.", player->getCName(), player->himHer());
			player->setGuildRank(GUILD_NONE);

			// Kick them out if they don't belong
			p = gConfig->getProperty(player->currentLocation.room);
			if(p && p->getGuild() == guildId)
				p->expelToExit(player, false);
		} else {
			player->print("As a leader of the guild, you may not leave it.  Transfer ownership to someone else first or Disband.\n");
		}
		return;
	}
	lowercize(cmnd->str[2], 1);
	target = gServer->findPlayer(cmnd->str[2]);
	bool online = true;

	if(!target) {
		online = false;
		if(!loadPlayer(cmnd->str[2], &target)) {
			player->print("That player does not exist.\n");
			return;
		}
	}

	if(target->getGuild() != guildId) {
		player->print("%s is not in your guild!\n", target->getCName());
		return;
	}
	if(target->getGuildRank() >= player->getGuildRank()) {
		player->print("You may only remove members of lower rank than you.\n");
		return;
	}
	if(target->getGuildRank() < GUILD_PEON) {
		player->print("%s is not in your guild!\n", target->getCName());
		return;
	}
	if(!canRemovePlyFromGuild(target)) {
		player->print("Guilds cannot drop below 3 players; the guild must be disbanded.\n");
		return;
	}

	updateGuild(target, GUILD_REMOVE);
	target->setGuild(0);
	target->setGuildRank(GUILD_NONE);
	target->print("You have been removed from your guild by %s.\n", player->getCName());
	player->print("You remove %s from your guild.\n", target->getCName());
	broadcastGuild(guildId, 1, "%s has been removed from your guild by %s.", target->getCName(), player->getCName());

	if(target->getForum() != "") {
		player->printColor("%s is associated with forum account ^C%s^x.\n", target->getCName(), target->getForum().c_str());
		player->printColor("You may wish to consider removing this account from the guild forum.\n");
	}

	std::list<Property*>::iterator pt;
	for(pt = gConfig->properties.begin(); pt != gConfig->properties.end(); pt++) {
		if((*pt)->isOwner(target->getName()) && (*pt)->getGuild() == guildId) {
			if((*pt)->getType() == PROP_SHOP) {
				shopRemoveGuild(*pt, target, 0, 0);
			} else {
				bstring output = (*pt)->getName();
				broadcast(isCt, "^r%s was removed from guild %d.\nProperty \"%s\" belongs to the guild, but is not a shop.", target, guildId, output.c_str());
			}
		}
	}

	// Kick them out if they don't belong
	p = gConfig->getProperty(target->currentLocation.room);
	if(p && p->getGuild() == guildId)
		p->expelToExit(target, !online);

	gConfig->saveProperties();
	if(!online)
		free_crt(target);
}

//*********************************************************************
//						promote
//*********************************************************************

void Guild::promote(Player* player, cmd* cmnd) {
	Player	*target=0;
	int newRank=0;
	char rank[80];

	if(!player->getGuild() || player->getGuildRank() != GUILD_MASTER) {
		player->print("You are not the guild leader.\n");
		return;
	}
	if(cmnd->num < 3) {
		printGuildSyntax(player);
		return;
	}
	lowercize(cmnd->str[2], 1);
	target = gServer->findPlayer(cmnd->str[2]);
	if(!target || !player->canSee(target)) {
		player->print("%s is not on.\n", cmnd->str[2]);
		return;
	}
	if(target->getGuild() != player->getGuild() || target->getGuildRank() < GUILD_PEON) {
		player->print("%s is not in your guild!\n", target->getCName());
		return;
	}
	if(cmnd->num == 4) {
		if(!strncmp(cmnd->str[3], "banker", strlen(cmnd->str[3])) && cmnd->num == 4) {
			strcpy(rank, "banker");
			newRank = GUILD_BANKER;
		} else { // if(!strncmp(cmnd->str[3], "officer", strlen(cmnd->str[3])) && cmnd->num == 4) {
			strcpy(rank, "officer");
			newRank = GUILD_OFFICER;
		}
	} else {
		if(target->getGuildRank() == GUILD_PEON) {
			newRank = GUILD_OFFICER;
			strcpy(rank, "officer");
		} else if(target->getGuildRank() == GUILD_OFFICER) {
			strcpy(rank, "banker");
			newRank = GUILD_BANKER;
		} else {
			strcpy(rank, "officer");
			newRank = GUILD_OFFICER;
		}
	}

	if(newRank <= target->getGuildRank()) {
		player->print("You cannot promote someone to an equal or lesser rank.\n");
		return;
	}

	target->setGuildRank(newRank);
	player->print("You promote %s to %s.\n", target, rank);
	target->print("You have been promoted to %s by %s.\n", rank, player->getCName());
	broadcastGuild(player->getGuild(), 1, "%s has been promoted to the rank of %s by %s.", target, rank, player->getCName());
}

//*********************************************************************
//						demote
//*********************************************************************

void Guild::demote(Player* player, cmd* cmnd) {
	Player	*target=0;
	int newRank=0;
	char rank[80];

	if(!player->getGuild() || player->getGuildRank() != GUILD_MASTER) {
		player->print("You are not the guild leader.\n");
		return;
	}
	if(cmnd->num < 3) {
		printGuildSyntax(player);
		return;
	}
	lowercize(cmnd->str[2], 1);
	target = gServer->findPlayer(cmnd->str[2]);
	if(!target || !player->canSee(target)) {
		player->print("%s is not on.\n", cmnd->str[2]);
		return;
	}
	if(target->getGuild() != player->getGuild() || target->getGuildRank() < GUILD_PEON) {
		player->print("%s is not in your guild!\n", target->getCName());
		return;
	}
	if(cmnd->num == 4) {
		if(!strncmp(cmnd->str[3], "officer", strlen(cmnd->str[3])) && cmnd->num == 4) {
			strcpy(rank, "officer");
			newRank = GUILD_OFFICER;
		} else { // if(!strncmp(cmnd->str[3], "member", strlen(cmnd->str[3])) && cmnd->num == 4) {
			strcpy(rank, "member");
			newRank = GUILD_PEON;
		}
	} else {
		if(target->getGuildRank() == GUILD_BANKER) {
			newRank = GUILD_OFFICER;
			strcpy(rank, "officer");
		} else { //if(target->getGuildRank() == GUILD_OFFICER) {
			strcpy(rank, "member");
			newRank = GUILD_PEON;
		}

	}

	if(newRank >= target->getGuildRank()) {
		player->print("You cannot demote someone to an equal or higher rank.\n");
		return;
	}

	target->setGuildRank(newRank);
	player->print("You demote %s to %s.\n", target, rank);
	target->print("You have been demoted to %s rank by %s.\n", rank, player->getCName());
	broadcastGuild(player->getGuild(), 1, "%s has been demoted to %s rank by %s.", target, rank, player->getCName());
}

//*********************************************************************
//						abdicate
//*********************************************************************

void Guild::abdicate(Player* player, Player* target, bool online) {
	int guildId = player->getGuild();

	if(!guildId || player->getGuildRank() != GUILD_MASTER) {
		player->print("You are not the leader of the guild.\n");
		return;
	}

	if(target->getGuild() != player->getGuild() || target->getGuildRank() < GUILD_PEON) {
		player->print("%s is not in your guild!\n", target->getCName());
		return;
	}


	target->setGuildRank(GUILD_MASTER);
	player->setGuildRank(GUILD_BANKER);

	target->print("You have been promoted to guild leader by %s.\n", player->getCName());
	target->print("Use the \"guild\" command to set your forum account as guildmaster of the guild board.\n");
	player->print("You promote %s to guild leader.\n", target->getCName());

	std::list<Property*>::iterator pt;
	bstring pName;
	for(pt = gConfig->properties.begin(); pt != gConfig->properties.end(); pt++) {
		if(	(*pt)->isOwner(player->getName()) &&
			(*pt)->getGuild() == guildId
		) {
			pName = gConfig->catRefName((*pt)->getArea());
			if((*pt)->getType() == PROP_GUILDHALL) {
				// guildhalls are easy - ownership transfers to the new guildmaster
				(*pt)->setOwner(target->getName());
				player->print("%s assumes ownership of the guildhall in %s.\n", target->getCName(), pName.c_str());
				target->print("You assume ownership of the guildhall in %s.\n", pName.c_str());
			} else if((*pt)->getType() == PROP_SHOP) {
				// shops located inside the guild transfer ownership to the new guildmaster
				CatRef cr = (*pt)->ranges.front().low;
				UniqueRoom* room=0;
				bool transferOwnership = false;

				if(loadRoom(cr, &room)) {
					// Look for the first exit linking to a guild
					if(shopStaysWithGuild(room))
						transferOwnership = true;
				}

				if(transferOwnership) {
					(*pt)->setOwner(target->getName());
					player->print("%s assumes ownership of the guild shop in %s.\n", target->getCName(), pName.c_str());
					target->print("You assume ownership of the guild shop in %s.\n", pName.c_str());
				} else {
					player->print("You retain ownership of the guild shop in %s.\n", pName.c_str());
				}
			}
		}
	}

	broadcastGuild(player->getGuild(), 1, "%s has been promoted to guild leader by %s.", target->getCName(), player->getCName());
	Guild* guild = gConfig->getGuild(guildId);

	guild->setLeader(target->getName());
	gConfig->saveGuilds();
	gConfig->saveProperties();

	player->save();
	target->save(online);

	std::ostringstream url;
	url << "mud.php?type=guildAbdicate&mud_id=" << guild->getNum() << "&char=" << target->getCName();
	callWebserver(url.str());
}

void Guild::abdicate(Player* player, cmd* cmnd) {
	Player	*target=0;
	int guildId = player->getGuild();

	if((!guildId || player->getGuildRank() != GUILD_MASTER) && cmnd->num >= 3) {
		player->print("You are not the leader of the guild.\n");
		return;
	}

	if(cmnd->num < 3) {
		player->print("Abdicate to whom?\n");
		return;
	}
	lowercize(cmnd->str[2], 1);
	target = gServer->findPlayer(cmnd->str[2]);

	if(!target || !player->canSee(target)) {
		player->print("%s is not on.\n", cmnd->str[2]);
		return;
	}

	Guild::abdicate(player, target, true);
}

//*********************************************************************
//						join
//*********************************************************************

void Guild::join(Player* player, cmd *cmnd) {
	bstring name = "";
	if(!player->getGuildRank()) {
		player->print("You have not been invited to join any guilds!\n");
		return;
	}
	if(player->getGuildRank() >= GUILD_PEON) {
		player->print("You are already in a guild.\n");
		return;
	}

	if(player->getLevel() < GUILD_JOIN_LEVEL) {
		player->print("You must be at least level %d to join a guild.\n", GUILD_JOIN_LEVEL);
		return;
	}

	if(player->getGuildRank() == GUILD_INVITED_OFFICER) {
		broadcastGuild(player->getGuild(), 1, "%s has joined your guild as an officer.", player->getCName());
		player->setGuildRank(GUILD_OFFICER);
	} else if(player->getGuildRank() == GUILD_INVITED_BANKER) {
		player->setGuildRank(GUILD_BANKER);
		broadcastGuild(player->getGuild(), 1, "%s has joined your guild as a banker.", player->getCName());
	} else { // Default to normal member
		broadcastGuild(player->getGuild(), 1, "%s has joined your guild as a normal member.", player->getCName());
		player->setGuildRank(GUILD_PEON);
	}

	updateGuild(player, GUILD_JOIN);
	name = getGuildName(player->getGuild());
	player->print("You have joined %s.\n", name.c_str());

	if(player->getForum() != "")
		callWebserver((bstring)"mud.php?type=autoguild&guild=" + name + "&user=" + player->getForum() + "&char=" + player->getCName());

}

//*********************************************************************
//						reject
//*********************************************************************

void Guild::reject(Player* player, cmd* cmnd) {
	if(!player->getGuild() || player->getGuildRank() >= GUILD_PEON) {
		player->print("You have no offer to reject.\n");
		return;
	}

	player->print("You reject the offer to join %s.\n", getGuildName(player->getGuild()));
	player->setGuild(0);
	player->setGuildRank(0);
}

//*********************************************************************
//						disband
//*********************************************************************

void Guild::disband(Player* player, cmd* cmnd) {
	if(!player->getGuild() || player->getGuildRank() < GUILD_MASTER) {
		player->print("You are not the guildmaster.\n");
		return;
	}
	int guildId = player->getGuild();
	Guild* guild = gConfig->getGuild(guildId);


	if(!guild->bank.isZero()) {
		player->print("You quickly swipe the guild's funds of %s!\n", guild->bank.str().c_str());
		player->coins.add(guild->bank);
	}

	broadcastGuild(guildId, 1, "Your guild has been disbanded by %s.", player->getCName());
	Player* ply;
	for(std::pair<bstring, Player*> p : gServer->players) {
		ply = p.second;

		if(!ply->getGuild() || ply->getGuild() != guildId)
			continue;
		ply->setGuild(0);
		ply->setGuildRank(0);
	}

	gConfig->deleteGuild(guildId);
}

//*********************************************************************
//						cmdGuildHall
//*********************************************************************

int cmdGuildHall(Player* player, cmd* cmnd) {
	Property::manage(player, cmnd, PROP_GUILDHALL, 1);
	return(0);
}

//*********************************************************************
//						doGuildSend
//*********************************************************************
// aka guildchat

void doGuildSend(const Guild *guild, Player* player, bstring txt) {
	if(!guild) {
		player->print("Invalid guild!\n");
		return;
	}

	broadcastGuild(guild->getNum(), 1, "### %s sent, \"%s\".",
		player->getCName(), escapeColor(txt).c_str());
	txt = escapeColor(txt);
	broadcast(watchingEaves, "^E--- [%s] %s guild sent, \"%s\".",
		guild->getName().c_str(), player->getCName(), txt.c_str());
}

//*********************************************************************
//						cmdGuildSend
//*********************************************************************

int cmdGuildSend(Player* player, cmd* cmnd) {
	bstring text = "";

	player->clearFlag(P_AFK);

	if(!player->ableToDoCommand())
		return(0);

	if(player->inJail()) {
		player->print("People in jail do not have that privilage.\n");
		return(0);
	}

	if(!player->getGuild() || player->getGuildRank() < GUILD_PEON) {
		player->print("You do not belong to a guild.\n");
		return(0);
	}

	text = getFullstrText(cmnd->fullstr, 1);
	if(text == "") {
		player->print("Send what?\n");
		return(0);
	}

	if(!player->canSpeak()) {
		player->printColor("^yYou are unable to do that right now.\n");
		return(0);
	}

	doGuildSend(gConfig->getGuild(player->getGuild()), player, text);
	return(0);
}

//*********************************************************************
//						dmApproveGuild
//*********************************************************************

int dmApproveGuild(Player* player, cmd* cmnd) {
	char guildName[41];
	GuildCreation * toApprove;
	int len,i=0,j=0;

	if(cmnd->num < 2) {
		player->print("Approve what guild?\n");
		return(0);
	}

	len = cmnd->fullstr.length();

	// Kill the first space
	while(i < len) {
		if(cmnd->fullstr[i] == ' ' && cmnd->fullstr[i+1] != ' ')
			j++;
		if(j==1)
			break;
		i++;
	}

	len = strlen(&cmnd->fullstr[i+1]);
	if(!len) {
		player->print("Approve what guild?\n");
		return(0);
	}

	if(len>40)
		cmnd->fullstr[40] = '\0';

	strcpy(guildName, &cmnd->fullstr[i+1]);
	toApprove = gConfig->findGuildCreation(guildName);
	if(toApprove == NULL) {
		player->print("'%s' is not currently up for creation.\n", guildName);
		return(0);
	}
	if(toApprove->status == GUILD_NEEDS_SUPPORT) {
		player->print("'%s' still needs support.\n", guildName);
		return(0);
	}
	player->print("You approve the guild '%s'.\n", guildName);
	broadcast(isCt, "^y%s just approved the guild %s", player->getCName(), guildName);

	gConfig->creationToGuild(toApprove);
	// saved by above function
	//gConfig->saveGuilds();
	return(0);
}

//*********************************************************************
//						dmRejectGuild
//*********************************************************************

int dmRejectGuild(Player* player, cmd* cmnd) {
	char guildName[41];
	char *reason=0;
	GuildCreation * toReject;
	int len,i=0,j=0, iTmp=0, strLen;

	strLen = cmnd->fullstr.length();

	// This kills all leading whitespace
	while(i<strLen && isspace(cmnd->fullstr[i]))
		i++;

	// This kills the command itself
	while(i<strLen && !isspace(cmnd->fullstr[i]))
		i++;

	// This kills all the white space before the guild
	while(i<strLen && isspace(cmnd->fullstr[i]))
		i++;

	len = strlen(&cmnd->fullstr[i]);
	if(!len) {
		player->print("Reject what guild?\n");
		return(0);
	}
	// This finds out how long the guild is
	// Keep going untill we get to the end of the string or a -
	while(i+j < strLen && cmnd->fullstr[i+j] != '\0' && cmnd->fullstr[i+j] != '-')
		j++;
	j = MIN(j, 40);
	memcpy(guildName, &cmnd->fullstr[i], j);
	guildName[j] = '\0';
	// Kill trailling whitespace
	len = strlen(guildName);
	if(!len) {
		player->print("Reject what guild?\n");
		return(0);
	}
	while(isspace(guildName[len-1]))
		len--;
	guildName[len] = '\0';
	player->print("Trying to reject '%s'\n", guildName);
	i = i+j;
	j=0;
	len = strlen(&cmnd->fullstr[i+1]);

	reason = strstr(&cmnd->fullstr[i], "-r ");
	if(reason) { // There is a reason string then
		iTmp = i;
		while(iTmp < strLen && &cmnd->fullstr[iTmp] != reason)
			iTmp++;
		reason += 3;
		while(isspace(*reason))
			reason++;
		// Kill trailing whitespace
		len = strlen(reason);
		while(isspace(reason[len-1]))
			len--;
		reason[len] = '\0';
	}
	if(iTmp) { // We have a reason, everything else stops at the beginging of the -r
		strLen = iTmp;
		cmnd->fullstr[iTmp] = '\0';
	}
	if(reason != 0) {
		player->print("Reason '%s'\n", reason);
	}
	toReject = gConfig->findGuildCreation(guildName);
	if(toReject == NULL) {
		player->print("'%s' is not currently up for creation.\n", guildName);
		return(0);
	}
	player->print("You reject the guild '%s'.\n", guildName);
	broadcast(isCt, "^y%s just rejected the guild %s", player->getCName(), guildName);
	rejectGuild(toReject, reason);
	gConfig->saveGuilds();
	return(0);
}

//*********************************************************************
//						showGuildsNeedingApproval
//*********************************************************************

void showGuildsNeedingApproval(Player* viewer) {
	GuildCreation *gcp;
	int num = 0;
	std::list<GuildCreation*>::iterator it;
	std::ostringstream oStr;

	for(it = gConfig->guildCreations.begin() ; it != gConfig->guildCreations.end() ; it++) {
		gcp = (*it);
		if(gcp->status != GUILD_AWAITING_APPROVAL)
			continue;

		num++;
		if(num == 1) {
			oStr << "\nGuilds needing approval:\n";
			oStr << "--------------------------------------------------------------------------------\n";
		}

		oStr << "^c" << num << ") " << gcp->name << " by " << gcp->leader << ".\n"
			 << "   " << gcp->numSupporters << " Supporter"
			 << (gcp->numSupporters != 1 ? "s" : "") << ":";

		std::map<bstring, bstring>::iterator sIt;
		for(sIt = gcp->supporters.begin() ; sIt != gcp->supporters.end() ; sIt++)
			oStr << " " << (*sIt).first;

		oStr << "\n";
	}

	viewer->printColor("%s", oStr.str().c_str());
}

//*********************************************************************
//						viewMembers
//*********************************************************************

void Guild::viewMembers(Player* player, cmd* cmnd) {
	if(cmnd->num < 3) {
		player->print("What guild were you looking for?\n\n");
		Guild::list(player, cmnd);
		return;
	}

	Guild *guild = gConfig->getGuild(player, getFullstrText(cmnd->fullstr, 2));
	if(!guild) {
		player->print("The guild you were looking for could not be found.\n");
		return;
	}

	player->print("Guild:   %s\nMembers: ", guild->name.c_str());

	std::list<bstring>::iterator it;
	bstring toPrint;
	for(it = guild->members.begin() ; it != guild->members.end() ; it++ ) {
		toPrint += (*it);
		toPrint += ", ";
	}
	toPrint[toPrint.length() - 2] = '.';
	player->printColor("^g%s^x\n", toPrint.c_str());

	if(player->isCt() || guild->getNum() == player->getGuild())
		guild->guildhallLocations(player, "Your guildhall is located at %s in %s.\n");
}

//*********************************************************************
//						list
//*********************************************************************

void Guild::list(Player* player, cmd* cmnd) {
	int num = 1;
	GuildCreation * gcp;

	player->printColor("^b    %-25s %-15s  Info\n", "Guild", "Leader");
	player->printColor("^b--------------------------------------------------------------------------------\n");

	std::map<int, Guild*>::iterator it;
	Guild *guild;
	for(it = gConfig->guilds.begin() ; it != gConfig->guilds.end() ; it++) {
		guild = (*it).second;

		player->printColor("%2d> ^c%-25s ^g%-15s ^x%2d Member(s)",
			num++, guild->name.c_str(), guild->leader.c_str(), guild->numMembers);
		if(guild->pkillsIn)
			player->printColor("^r (Pk:%3d%%)", pkillPercent(guild->pkillsWon, guild->pkillsIn));
		else
			player->printColor("^r (Pk: N/A)");
		player->printColor("^y Avg Lvl: %2d\n", guild->averageLevel());
	}
	std::list<GuildCreation*>::iterator gcIt;
	for(gcIt = gConfig->guildCreations.begin() ; gcIt != gConfig->guildCreations.end() ; gcIt++) {
		gcp = (*gcIt);
		if(gcp->status != GUILD_NEEDS_SUPPORT)
			continue;
		num ++;
		if(num == 1) {
			player->print("\nGuilds needing support\n");
			player->print("--------------------------------------------------------------------------------\n");
		}
		player->printColor("^c%d) %s by %s.\n", num, gcp->name.c_str(), gcp->leader.c_str());
		player->print("   %d Supporter%s: ", gcp->numSupporters, gcp->numSupporters != 1 ? "s" : "");

		std::map<bstring, bstring>::iterator sIt;
		for(sIt = gcp->supporters.begin() ; sIt != gcp->supporters.end() ; sIt++) {
			player->print("%s", (*sIt).first.c_str());
		}

		player->print("\n");
	}
}

//*********************************************************************
//						dmListGuilds
//*********************************************************************
// List currently created guilds, and guilds being opted for creation

int dmListGuilds(Player* player, cmd* cmnd) {
	GuildCreation * gcp;
	int		found = 0;

	//player->print("Max Guild Id:  %d\n", gConfig->maxGuilds);
	player->print("Next Guild Id: %d\n\n", gConfig->nextGuildId);
	//	gp = firstGuild;

	//	while(gp) {
	std::map<int, Guild*>::iterator it;
	Guild *guild;
	for(it = gConfig->guilds.begin() ; it != gConfig->guilds.end() ; it++) {
		guild = (*it).second;

		player->printColor("^CGuild: ");
		player->printColor("^c%3d %-40s", guild->getNum(), guild->getName().c_str());
		player->print("Leader: %s\n", guild->getLeader().c_str());
		player->print("  NumMembers: %3d ", guild->getNumMembers());
		player->print(" Avg Level: %3d ", guild->averageLevel());
		player->print(" Total Levels %3d\n", guild->getLevel());
		player->printColor("  Members: ^g");
		std::list<bstring>::iterator mIt;
		bstring toPrint;
		for(mIt = guild->members.begin() ; mIt != guild->members.end() ; mIt++ ) {
			toPrint += (*mIt);
			toPrint += ", ";
		}
		toPrint[toPrint.length() - 2] = '.';
		player->printColor("%s\n", toPrint.c_str());

		player->print("  Pkills: %d/%d (%d%%) ", guild->getPkillsWon(), guild->getPkillsIn(), pkillPercent(guild->getPkillsWon(), guild->getPkillsIn()));
		player->print(" Points: %d\n", guild->getPoints());
		player->print("  GuildBank:   %s\n", guild->bank.str().c_str());
		guild->guildhallLocations(player, "  Guildhall: %s in %s\n");
	}
	player->print("\nGuilds being supported by players for creation:\n");
	std::list<GuildCreation*>::iterator gcIt;
	for(gcIt = gConfig->guildCreations.begin() ; gcIt != gConfig->guildCreations.end() ; gcIt++) {
		gcp = (*gcIt);
		found++;
		player->printColor("%s%d) %s by %s.\n", gcp->status == GUILD_NEEDS_SUPPORT ? "^c" : "^g",
				found, gcp->name.c_str(), gcp->leader.c_str());
		player->print("   %d Supporter%s:", gcp->numSupporters, gcp->numSupporters != 1 ? "s" : "");
		std::map<bstring, bstring>::iterator sIt;
		for(sIt = gcp->supporters.begin() ; sIt != gcp->supporters.end() ; sIt++) {
			player->print(" %s", (*sIt).first.c_str());
		}
		player->print("\n");
	}
	if(found == 0)
		player->printColor("^x  None.\n");
	return(0);
}

//*********************************************************************
//						guild membership functions
//*********************************************************************

bool Guild::addMember(bstring memberName) {
	if(memberName != "") {
		members.push_back(memberName);
		return(true);
	}
	return(false);
}

bool Guild::delMember(bstring memberName) {
	std::list<bstring>::iterator mIt;

	for(mIt = members.begin() ; mIt != members.end() ; mIt++) {
		if(memberName == (*mIt)) {
			members.erase(mIt);
			return(true);
		}
	}
	return(false);
}

bool Guild::isMember(bstring memberName) {
	std::list<bstring>::iterator mIt;

	for(mIt = members.begin() ; mIt != members.end() ; mIt++) {
		if(memberName == (*mIt))
			return(true);
	}
	return(false);
}

void Guild::renameMember(bstring oldName, bstring newName) {
	std::list<bstring>::iterator mIt;

	if(leader == oldName)
		leader = newName;

	for(mIt = members.begin() ; mIt != members.end() ; mIt++) {
		if(oldName == (*mIt)) {
			(*mIt) = newName;
			break;
		}
	}
}


//*********************************************************************
//						addGuildCreation
//*********************************************************************

bool Config::addGuildCreation(GuildCreation* toAdd) {
	guildCreations.push_back(toAdd);
	return(true);
}

//*********************************************************************
//						supporter functions
//*********************************************************************

bool GuildCreation::addSupporter(Player* supporter) {
	if(supporter && supporters.find(supporter->getName()) == supporters.end()) {
		supporters[supporter->getName()] = supporter->getSock()->getIp();
		numSupporters++;
		return(true);
	}
	return(false);
}

bool GuildCreation::removeSupporter(bstring supporterName) {
	if(supporters.find(supporterName) != supporters.end()) {
		supporters.erase(supporterName);
		numSupporters--;
		return(true);
	}
	return(false);
}

void GuildCreation::renameSupporter(bstring oldName, bstring newName) {
	if(leader == oldName)
		leader = newName;

	if(supporters.find(oldName) != supporters.end()) {
		supporters[newName] = supporters[oldName];
		supporters.erase(oldName);
	}
}

void Config::guildCreationsRenameSupporter(bstring oldName, bstring newName) {
	std::list<GuildCreation*>::iterator gcIt;
	for(gcIt = guildCreations.begin(); gcIt != guildCreations.end(); gcIt++) {
		(*gcIt)->renameSupporter(oldName, newName);
	}
}



//*********************************************************************
//						findGuildCreation
//*********************************************************************

GuildCreation* Config::findGuildCreation(bstring creationName) {
	std::list<GuildCreation*>::iterator gcIt;
	GuildCreation* gcp;
	for(gcIt = guildCreations.begin(); gcIt != guildCreations.end(); gcIt++) {
		gcp = (*gcIt);
		if(gcp->name == creationName)
			return(gcp);
	}
	return(NULL);
}

//*********************************************************************
//						recalcLevel
//*********************************************************************
// this function is slow, so we don't want this to happen.

void Guild::recalcLevel() {
	std::list<bstring>::iterator mIt;
	Player* member=0;
	bool	online;

	broadcast(isCt, "\n^yError: Guild level for \"%s\" is being recalculated.\n", name.c_str());

	level = 0;
	for(mIt = members.begin() ; mIt != members.end() ; mIt++) {
		online = false;
		member = gServer->findPlayer((*mIt).c_str());
		if(!member) {
			if(!loadPlayer((*mIt).c_str(), &member))
				continue;
		} else
			online = true;

		level += member->getLevel();

		if(!online)
			free_crt(member);
	}

	gConfig->saveGuilds();
}

//*********************************************************************
//						averageLevel
//*********************************************************************

int Guild::averageLevel() {
	int cLevel, cMembers;

	if(!level)
		recalcLevel();

	cLevel = MAX(1, level);
	cMembers = MAX(1, numMembers);

	return(cLevel/cMembers);
}

//*********************************************************************
//						guildExists
//*********************************************************************

bool Config::guildExists(bstring guildName) {
	Guild* guild;
	guild = getGuild(guildName);
	if(guild)
		return(true);

	GuildCreation* gcp;
	gcp = findGuildCreation(guildName);
	if(gcp)
		return(true);

	return(false);
}

//*********************************************************************
//						getGuildName
//*********************************************************************

const char *getGuildName(int guildNum) {
	Guild* guild = gConfig->getGuild(guildNum);
	if(guild)
		return(guild->getName().c_str());
	else
		return("Unknown Guild");
}


//*********************************************************************
//						canRemovePlyFromGuild
//*********************************************************************
// True only if the guild will still have 3 or more players in it
// otherwise it must be disbanded

bool canRemovePlyFromGuild(Player* player) {
	const Guild* guild  = gConfig->getGuild(player->getGuild());
	if(!guild)
		return(false);
	if(guild->getNumMembers() > 3)
		return(true);
	return(false);
}

//*********************************************************************
//						updateGuild
//*********************************************************************
// Updates level statistics based upon the player, and 'what' is happening

void updateGuild(Player* player, int what) {
	if(!player || !player->getGuild() || player->getGuildRank() < GUILD_PEON)
		return;
	std::ostringstream url;

	Guild *guild = gConfig->getGuild(player->getGuild());
	if(!guild)
		return;
	if(what == GUILD_JOIN) {
		guild->incLevel(player->getLevel());
		guild->incNumMembers();
		guild->addMember(player->getName());
		url << "mud.php?type=guildAddMember&mud_id=" << guild->getNum() << "&char=" << player->getCName();
	} else if(what == GUILD_REMOVE) {
		bool online=false;

		guild->incNumMembers(-1);

		// There will be nobody is left in the guild!
		if(!guild->getNumMembers()) {
			// This invalidates the "guild" variable. It will also take care of saving
			// the guild and destroying guild  property, so we can stop what we're doing.
			gConfig->deleteGuild(player->getGuild());
			return;
		}

		guild->incLevel(player->getLevel() * -1);
		guild->delMember(player->getName());

		// the guildmaster is leaving and did not abdicate their position!
		// find someone to take their place
		if(player->getGuildRank() == GUILD_MASTER) {
			Player* leader=0;

			do {
				guild->setLeader(guild->members.front());

				leader = gServer->findPlayer(guild->getLeader().c_str());
				if(leader)
					online = true;
				else {
					online = false;
					if(!loadPlayer(guild->getLeader().c_str(), &leader))
						leader = 0;
				}


				if(leader) {
					Guild::abdicate(player, leader, online);

					if(!online)
						free_crt(leader);
					break;
				}

				// If we couldn't load a member, we've got data integrity problems
				guild->setLevel(0);
				guild->setLeader("");
				guild->incNumMembers(-1);
				guild->members.pop_front();
			} while(guild->members.size());
		}

		// If we're removing, find the forum account. If any remaining members are associated
		// with this forum account, don't remove the forum account from the guild
		std::list<bstring>::const_iterator it;

		if(player->getForum() != "") {
			Player* target=0;
			bool removeForum = true;

			for(it = guild->members.begin(); it != guild->members.end(); it++) {
				target = gServer->findPlayer((*it).c_str());
				if(target)
					online = true;
				else {
					online = false;
					if(!loadPlayer((*it).c_str(), &target))
						target = 0;
				}


				if(target) {
					// if another member of this guild has the same forum account, don't remove the account
					if(player->getForum() == target->getForum())
						removeForum = false;
					if(!online)
						free_crt(target);
				}

				if(!removeForum)
					break;
			}

			if(removeForum)
				url << "mud.php?type=guildRemoveMember&mud_id=" << guild->getNum() << "&char=" << player->getName();
		}

	} else if(what == GUILD_LEVEL) {
		guild->incLevel();
	} else if(what == GUILD_DIE) {
		guild->incLevel(-1);
	}
	gConfig->saveGuilds();
	callWebserver(url.str());
}

//*********************************************************************
//						creationToGuild
//*********************************************************************

void Config::creationToGuild(GuildCreation* toApprove) {
	std::map<bstring, bstring>::iterator sIt;
	Player *leader=0, *officer=0;
	int		guildId=0;
	bool	online=false;
	std::ostringstream url;
	url << "mud.php?type=guildCreate&char=" << toApprove->leader;

	// The suicide/*dust commands will take care of leaders / supporters
	// suiciding. These are extra checks in case anyone somehow sneaks past.

	// If the leader doesn't exist, we delete the guild.
	leader = gServer->findPlayer(toApprove->leader.c_str());
	if(!leader) {
		if(!loadPlayer(toApprove->leader.c_str(), &leader)) {
			broadcast(isCt, "^yError creating guild '%s': Can't find the leader %s.\nThis guild is being erased.",
				toApprove->name.c_str(), toApprove->leader.c_str());
			removeGuildCreation(toApprove->leader);
			return;
		}
	} else
		online = true;


	// If they suicide and remake a character with the same name, don't
	// let a level 1 character become the leader of the guild.
	if(!leader->flagIsSet(P_CREATING_GUILD)) {
		broadcast(isCt, "^yError creating guild '%s': %s is not flagged as creating a guild.\nThis guild is being erased.^",
			toApprove->name.c_str(), toApprove->leader.c_str());
		removeGuildCreation(leader->getName());
		if(!online)
			free_crt(leader);
		return;
	}


	// If we can't load the supporters
	for(sIt = toApprove->supporters.begin() ; sIt != toApprove->supporters.end() ; sIt++) {
		if(!gServer->findPlayer((*sIt).first.c_str())) {
			if(!loadPlayer((*sIt).first.c_str(), &officer)) {
				broadcast(isCt, "^yError loading guild supporter %s in guild %s.\nRemoving this person from the support list.", (*sIt).first.c_str(), toApprove->name.c_str());
				toApprove->removeSupporter((*sIt).first);
				return;
			}
			free_crt(officer);
		}
	}


	// Everything has checked out - create the guild.
	guildId = nextGuildId;
	url << "&mud_id=" << guildId;

	nextGuildId++;
	numGuilds++;
	Guild* guild = new Guild;

	guild->setName(toApprove->name);
	url << "&guildName=" << toApprove->name;

	guild->setLeader(toApprove->leader);
	guild->setNum(guildId);
	guild->setPkillsWon(0);
	guild->setPkillsIn(0);
	guild->setPoints(0);

	guild->setLevel(leader->getLevel());
	guild->setNumMembers(1);

	// Set the leader
	leader->setGuild(guildId);
	leader->setGuildRank(GUILD_MASTER);
	leader->clearFlag(P_CREATING_GUILD);
	leader->save(online);

	guild->addMember(leader->getName());

	addGuild(guild);

	if(online)
		leader->print("You are now the leader of %s.\n", guild->getName().c_str());

	for(sIt = toApprove->supporters.begin() ; sIt != toApprove->supporters.end() ; sIt++) {
		bool offOnline = false;
		url << "&supporter[]=" << (*sIt).first;

		officer = gServer->findPlayer((*sIt).first.c_str());
		if(!officer) {
			if(!loadPlayer((*sIt).first.c_str(), &officer)) {
				broadcast(isCt, "^yError making %s an officer in %s.", (*sIt).first.c_str(), guild->getName().c_str());
				continue;
			}
		} else
			offOnline = true;
		officer->setGuild(guildId);
		officer->setGuildRank(GUILD_OFFICER);
		officer->clearFlag(P_CREATING_GUILD);
		officer->save(offOnline);

		guild->incNumMembers();
		guild->incLevel( officer->getLevel());
		guild->addMember(officer->getName());
		if(!offOnline)
			free_crt(officer);
		else
			officer->print("You are now an officer of %s.\n", guild->getName().c_str());
	}

	removeGuildCreation(leader->getName());
	if(!online)
		free_crt(leader);

	callWebserver(url.str());
}


//*********************************************************************
//						rejectGuild
//*********************************************************************

void rejectGuild(GuildCreation * toReject, char *reason) {
	Player	*leader=0, *officer=0;
	bstring leaderName = "";
	int		error = 0, ff;
	char	Reason[250], file[80], outStr[1024], datestr[40];
	long	t;
	bool	online=false;


	if(reason == 0)
		strcpy(Reason, "No reason given.\n");
	else
		strcpy(Reason, reason);

	leader = gServer->findPlayer(toReject->leader.c_str());
	if(!leader) {
		if(!loadPlayer(toReject->leader.c_str(), &leader)) {
			broadcast(isCt, "^yError rejecting guild '%s': Can't find the leader %s.", toReject->name.c_str(), toReject->leader.c_str());
			error = 1;
		}
	} else
		online = true;

	if(error == 0) {
		leaderName = leader->getName();
		leader->clearFlag(P_CREATING_GUILD);
		leader->save(online);

		if(!online) {
			// Send them a mudmail
			sprintf(file, "%s/%s.txt", Path::Post, leader->getCName());
			ff = open(file, O_CREAT | O_APPEND | O_RDWR, ACC);
			if(ff > 0) {
				time(&t);
				strcpy(datestr, (char *) ctime(&t));
				datestr[strlen(datestr) - 1] = 0;
				sprintf(outStr, "\n--..__..--..__..--..__..--..__..--..__..--..__..--..__..--..__..--..__..--\n\nMail from System (%s):\n\nYour guild '%s' has been rejected.\nReason: %s\n", datestr, toReject->name.c_str(), Reason);
				write(ff, outStr, strlen(outStr));
				close(ff);
				leader->setFlag(P_UNREAD_MAIL);
			}
			free_crt(leader);
		} else
			leader->print("Your guild %s has been rejected.\nReason: %s\n", toReject->name.c_str(), Reason);

	} else
		error = 0;

	std::map<bstring, bstring>::iterator sIt;
	for(sIt = toReject->supporters.begin() ; sIt != toReject->supporters.end() ; sIt++) {
		online = false;
		officer = gServer->findPlayer((*sIt).first.c_str());
		if(!officer) {
			if(!loadPlayer((*sIt).first.c_str(), &officer))
				continue;
		} else
			online = true;
		officer->clearFlag(P_CREATING_GUILD);
		officer->save(online);
		if(!online)
			free_crt(officer);
	}

	gConfig->removeGuildCreation(leaderName);
}


//*********************************************************************
//						removeGuildCreation
//*********************************************************************

bstring Config::removeGuildCreation(bstring leaderName) {
	std::list<GuildCreation*>::iterator it;
	GuildCreation *gc;
	bstring toReturn = "";
	for(it = gConfig->guildCreations.begin() ; it != gConfig->guildCreations.end() ; it++) {
		gc = (*it);
		if(gc && gc->leader == leaderName) {
			// We found the one we want to erase
			guildCreations.erase(it);
			toReturn = gc->name;
			delete gc;
			saveGuilds();
			return(toReturn);
		}
	}
	return("");
}

//*********************************************************************
//						getGuild
//*********************************************************************

Guild* Config::getGuild(const bstring& name) {
	Guild* guild=0;
	std::map<int, Guild*>::iterator it;
	for(it = guilds.begin(); it != guilds.end(); it++) {
		guild = (*it).second;
		if(guild->getName() == name)
			return(guild);
	}
	return (NULL);
}

Guild* Config::getGuild(int guildId) {
	if(guilds.find(guildId) != guilds.end())
		return(guilds[guildId]);
	return(0);
}

// Will find a guild based on "txt". If a guild could not be found, it
// will print a message to the player informing them of such.

Guild* Config::getGuild(const Player* player, bstring txt) {
	Guild* guild=0;
	// 0 = not found, -1 = not unique
	int check = 0, len = txt.getLength();
	txt = txt.toLower();

	std::map<int, Guild*>::iterator it;
	for(it = gConfig->guilds.begin(); it != gConfig->guilds.end(); it++) {

		if((*it).second->getName().left(len).toLower() == txt) {
			if(!check) {
				check = 1;
				guild = (*it).second;
			} else
				check = -1;
		}
	}

	if(!check) {
		player->print("Guild not found.\n");
		return(0);
	} else if(check == -1) {
		player->print("Guild name was not unique.\n");
		return(0);
	}

	return(guild);
}

//*********************************************************************
//						deleteGuild
//*********************************************************************
// When calling this function, it is your responsibility to save the guild
// leader (they get the guild's money).

bool Config::deleteGuild(int guildId) {
	if(guilds.find(guildId) == guilds.end())
		return(false);

	Guild* guild = guilds[guildId];
	guilds.erase(guildId);

	Player *player = gServer->findPlayer(guild->getLeader().c_str());
	bool online = true;
	if(!player) {
		online = false;
		if(!loadPlayer(guild->getLeader().c_str(), &player))
			player = 0;
	}

	if(player) {
		// Destroy guild property
		std::list<Property*>::iterator it;
		for(it = gConfig->properties.begin() ; it != gConfig->properties.end() ;) {
			if(guildId != (*it)->getGuild()) {
				it++;
				continue;
			}

			if((*it)->getType() == PROP_SHOP) {
				// If the shop is located inside the guildhall, then destroy it.
				// If it isn't, then unlink it.
				CatRef cr = (*it)->ranges.front().low;
				UniqueRoom* shop=0;
				if(loadRoom(cr, &shop)) {
					// If the shop belongs to the guild, remove and continue
					if(!shop->exits.empty() && !shopStaysWithGuild(shop)) {
						shopRemoveGuild(*it, player, shop, 0);
						it++;
						continue;
					}
				}
			}

			(*it)->destroy();
			it = properties.erase(it);
		}

		if(!online)
			free_crt(player);
	}

	std::ostringstream url;
	url << "mud.php?type=guildDisband&mud_id=" << guild->getNum();
	callWebserver(url.str());

	delete guild;
	saveGuilds();
	return(true);
}

//*********************************************************************
//						addGuild
//*********************************************************************

bool Config::addGuild(Guild* toAdd) {
	if(!toAdd || !toAdd->getNum())
		return(false);
	guilds[toAdd->getNum()] = toAdd;
	return(true);
}


// Clears the global list of guilds
void Config::clearGuildList() {
	std::map<int, Guild*>::iterator it;
	Guild* guild;

	for(it = guilds.begin(); it != guilds.end(); it++) {
		guild = (*it).second;
		delete guild;
		//guilds.erase(it);
	}
	guilds.clear();

	std::list<GuildCreation*>::iterator gcIt;
	GuildCreation* gcp;
	while(!guildCreations.empty()) {
		gcp = guildCreations.front();
		delete gcp;
		guildCreations.pop_front();
	}
	guildCreations.clear();
}