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/
/*
 * factions.cpp
 *	 Faction code.
 *   ____            _
 *  |  _ \ ___  __ _| |_ __ ___  ___
 *  | |_) / _ \/ _` | | '_ ` _ \/ __|
 *  |  _ <  __/ (_| | | | | | | \__ \
 *  |_| \_\___|\__,_|_|_| |_| |_|___/
 *
 * Permission to use, modify and distribute is 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 "factions.h"
#include "guilds.h"
#include "clans.h"
#include "commands.h"
#include <iomanip>

//*********************************************************************
//						FactionRegard
//*********************************************************************

FactionRegard::FactionRegard() {
	memset(classRegard, 0, sizeof(classRegard));
	memset(raceRegard, 0, sizeof(raceRegard));
	memset(deityRegard, 0, sizeof(deityRegard));
	vampirismRegard = 0;
	lycanthropyRegard = 0;
	overallRegard = 0;
}

void FactionRegard::load(xmlNodePtr rootNode) {
	xmlNodePtr curNode = rootNode->children;
	bstring temp = "";
	int id=0;

	while(curNode) {
		if(NODE_NAME(curNode, "Class")) {
			xml::copyPropToBString(temp, curNode, "Name");
			xml::copyToNum(classRegard[gConfig->classtoNum(temp)], curNode);
		}
		else if(NODE_NAME(curNode, "Race")) {
			xml::copyPropToBString(temp, curNode, "Name");
			xml::copyToNum(raceRegard[gConfig->racetoNum(temp)], curNode);
		}
		else if(NODE_NAME(curNode, "Deity")) {
			xml::copyPropToBString(temp, curNode, "Name");
			xml::copyToNum(deityRegard[gConfig->deitytoNum(temp)], curNode);
		}
		else if(NODE_NAME(curNode, "Vampirism")) xml::copyToNum(vampirismRegard, curNode);
		else if(NODE_NAME(curNode, "Lycanthropy")) xml::copyToNum(lycanthropyRegard, curNode);
		else if(NODE_NAME(curNode, "Guild")) {
			id = xml::getIntProp(curNode, "Id");
			guildRegard[id] = xml::toNum<long>(curNode);
		}
		else if(NODE_NAME(curNode, "Clan")) {
			id = xml::getIntProp(curNode, "Id");
			clanRegard[id] = xml::toNum<long>(curNode);
		}
		else if(NODE_NAME(curNode, "Overall")) xml::copyToNum(overallRegard, curNode);

		curNode = curNode->next;
	}
}

long FactionRegard::getClassRegard(int i) const {
	return(classRegard[i]);
}
long FactionRegard::getRaceRegard(int i) const {
	return(raceRegard[i]);
}
long FactionRegard::getDeityRegard(int i) const {
	return(deityRegard[i]);
}

long FactionRegard::getVampirismRegard() const {
	return(vampirismRegard);
}
long FactionRegard::getLycanthropyRegard() const {
	return(lycanthropyRegard);
}
long FactionRegard::getGuildRegard(int i) const {
	if(!i)
		return(0);
	std::map<int,long>::const_iterator it = guildRegard.find(i);
	if(it != guildRegard.end())
		return((*it).second);
	return(0);
}
long FactionRegard::getClanRegard(int i) const {
	if(!i)
		return(0);
	std::map<int,long>::const_iterator it = clanRegard.find(i);
	if(it != clanRegard.end())
		return((*it).second);
	return(0);
}

long FactionRegard::getOverallRegard() const {
	return(overallRegard);
}
//*********************************************************************
//						guildDisplay
//*********************************************************************

bstring FactionRegard::guildDisplay() const {
	std::map<int,long>::const_iterator it;
	std::ostringstream oStr;
	const Guild* guild=0;
	for(it = guildRegard.begin() ; it != guildRegard.end() ; it++) {
		guild = gConfig->getGuild((*it).first);

		oStr << "Guild(" << (*it).first << "-" << (guild ? guild->getName() : "invalid guild") << "):"
			<< Faction::getColor((*it).second)
			<< (*it).second << "^X ";
	}
	return(oStr.str());
}

//*********************************************************************
//						clanDisplay
//*********************************************************************

bstring FactionRegard::clanDisplay() const {
	std::map<int,long>::const_iterator it;
	std::ostringstream oStr;
	const Clan* clan=0;
	for(it = clanRegard.begin() ; it != clanRegard.end() ; it++) {
		clan = gConfig->getClan((*it).first);

		oStr << "Clan(" << (*it).first << "-" << (clan && clan->getId() == (unsigned int)(*it).first ? clan->getName() : "invalid clan") << "):"
			<< Faction::getColor((*it).second)
			<< (*it).second << "^X ";
	}
	return(oStr.str());
}

//*********************************************************************
//						Faction
//*********************************************************************

Faction::Faction() {
	name = displayName = social = parent = group = "";
	baseRegard = 0;
	is_parent = false;
}


void Faction::load(xmlNodePtr rootNode) {
	xmlNodePtr curNode = rootNode->children;

	while(curNode) {
			 if(NODE_NAME(curNode, "Name")) { xml::copyToBString(name, curNode); }
		else if(NODE_NAME(curNode, "DisplayName")) { xml::copyToBString(displayName, curNode); }
		else if(NODE_NAME(curNode, "Parent")) { xml::copyToBString(parent, curNode); }
		else if(NODE_NAME(curNode, "Group")) { xml::copyToBString(group, curNode); }
		else if(NODE_NAME(curNode, "Social")) { xml::copyToBString(social, curNode); }
		else if(NODE_NAME(curNode, "BaseRegard")) { xml::copyToNum( baseRegard, curNode); }
		else if(NODE_NAME(curNode, "InitialRegard")) initial.load(curNode);
		else if(NODE_NAME(curNode, "MaxRegard")) max.load(curNode);
		else if(NODE_NAME(curNode, "MinRegard")) min.load(curNode);
		curNode = curNode->next;
	}
}

bstring Faction::getName() const {
	return(name);
}
bstring Faction::getDisplayName() const {
	return(displayName);
}
bstring Faction::getParent() const {
	return(parent);
}
bstring Faction::getGroup() const {
	return(group != "" ? group : "Other");
}
bstring Faction::getSocial() const {
	return(social);
}
long Faction::getBaseRegard() const {
	return(baseRegard);
}
long Faction::getClassRegard(int i) const {
	return(initial.getClassRegard(i));
}
long Faction::getRaceRegard(int i) const {
	return(initial.getRaceRegard(i));
}
long Faction::getDeityRegard(int i) const {
	return(initial.getDeityRegard(i));
}
long Faction::getVampirismRegard() const {
	return(initial.getVampirismRegard());
}
long Faction::getLycanthropyRegard() const {
	return(initial.getLycanthropyRegard());
}
long Faction::getGuildRegard(int i) const {
	return(initial.getGuildRegard(i));
}
long Faction::getClanRegard(int i) const {
	return(initial.getClanRegard(i));
}
const FactionRegard* Faction::getInitial() {
	return(&initial);
}
const FactionRegard* Faction::getMax() {
	return(&max);
}
const FactionRegard* Faction::getMin() {
	return(&min);
}
//*********************************************************************
//						getInitialRegard
//*********************************************************************

long Faction::getInitialRegard(const Player* player) const {
	long regard = baseRegard;
	regard += initial.getClassRegard(player->getClass());
	// illusioned race affects faction
	regard += initial.getRaceRegard(player->getDisplayRace());
	if(player->getDeity())
		regard += initial.getDeityRegard(player->getDeity());
	if(player->isNewVampire())
		regard += initial.getVampirismRegard();
	if(player->isNewWerewolf())
		regard += initial.getLycanthropyRegard();
	if(player->getGuild())
		regard += initial.getGuildRegard(player->getGuild());
	if(player->getClan())
		regard += initial.getClanRegard(player->getClan());
	return(regard);
}

//*********************************************************************
//						alwaysHates
//*********************************************************************

bool Faction::alwaysHates(const Player* player) const {
	if(initial.getClassRegard(player->getClass()) == ALWAYS_HATE)
		return(true);
	if(initial.getRaceRegard(player->getRace()) == ALWAYS_HATE)
		return(true);
	if(player->getDeity() && initial.getDeityRegard(player->getDeity()) == ALWAYS_HATE)
		return(true);
	if(player->isNewVampire() && initial.getVampirismRegard() == ALWAYS_HATE)
		return(true);
	if(player->isNewWerewolf() && initial.getLycanthropyRegard() == ALWAYS_HATE)
		return(true);
	if(player->getGuild() && initial.getGuildRegard(player->getGuild()) == ALWAYS_HATE)
		return(true);
	if(player->getClan() && initial.getClanRegard(player->getClan()) == ALWAYS_HATE)
		return(true);
	return(false);
}

//*********************************************************************
//						getUpperLimit
//*********************************************************************

long Faction::getUpperLimit(const Player* player) const {
	long 	limit = MAX, x;
	x = max.getClassRegard(player->getClass());
	if(x) limit = MIN(x, limit);

	x = max.getRaceRegard(player->getRace());
	if(x) limit = MIN(x, limit);

	if(player->getDeity()) {
		x = max.getDeityRegard(player->getDeity());
		if(x) limit = MIN(x, limit);
	}
	if(player->isNewVampire()) {
		x = max.getVampirismRegard();
		if(x) limit = MIN(x, limit);
	}
	if(player->isNewWerewolf()) {
		x = max.getLycanthropyRegard();
		if(x) limit = MIN(x, limit);
	}
	if(player->getGuild()) {
		x = max.getGuildRegard(player->getGuild());
		if(x) limit = MIN(x, limit);
	}
	if(player->getClan()) {
		x = max.getClanRegard(player->getClan());
		if(x) limit = MIN(x, limit);
	}

	x = max.getOverallRegard();
	if(x) limit = MIN(x, limit);

	return(limit - getInitialRegard(player));
}

//*********************************************************************
//						getLowerLimit
//*********************************************************************

long Faction::getLowerLimit(const Player* player) const {
	long 	limit = MIN, x;
	x = min.getClassRegard(player->getClass());
	if(x) limit = MAX(x, limit);

	x = min.getRaceRegard(player->getRace());
	if(x) limit = MAX(x, limit);

	if(player->getDeity()) {
		x = min.getDeityRegard(player->getDeity());
		if(x) limit = MAX(x, limit);
	}
	if(player->isNewVampire()) {
		x = min.getVampirismRegard();
		if(x) limit = MAX(x, limit);
	}
	if(player->isNewWerewolf()) {
		x = min.getLycanthropyRegard();
		if(x) limit = MAX(x, limit);
	}
	if(player->getGuild()) {
		x = min.getGuildRegard(player->getGuild());
		if(x) limit = MAX(x, limit);
	}
	if(player->getClan()) {
		x = min.getClanRegard(player->getClan());
		if(x) limit = MAX(x, limit);
	}

	x = min.getOverallRegard();
	if(x) limit = MAX(x, limit);

	return(limit - getInitialRegard(player));
}

//*********************************************************************
//						getFaction
//*********************************************************************

const Faction *Config::getFaction(bstring factionStr) const {
	if(factionStr == "")
		return(0);
	std::map<bstring, Faction*>::const_iterator it = factions.find(factionStr);

	if(it != factions.end())
		return((*it).second);
	return(0);
}

//*********************************************************************
//						findAggro
//*********************************************************************

Player* Faction::findAggro(BaseRoom *room) {
	return(0);
}

//*********************************************************************
//						isParent
//*********************************************************************

bool Faction::isParent() const {
	return(is_parent);
}

//*********************************************************************
//						setIsParent
//*********************************************************************

void Faction::setParent(bstring value) {
	parent = value;
}

//*********************************************************************
//						setIsParent
//*********************************************************************

void Faction::setIsParent(bool value) {
	is_parent = value;
}

//*********************************************************************
//						showRegard
//*********************************************************************

void showRegard(const Player* viewer, bstring type, const FactionRegard* regard) {
	int a;
	std::ostringstream oStr;

	for(a=0; a < CLASS_COUNT; a++) {
		if(regard->getClassRegard(a)) {
			oStr << getClassAbbrev(a) << ":"
				<< Faction::getColor(regard->getClassRegard(a))
				<< regard->getClassRegard(a) << "^X ";
		}
	}
	for(a=0; a < RACE_COUNT; a++) {
		if(regard->getRaceRegard(a)) {
			oStr << gConfig->getRace(a)->getAbbr() << ":"
				<< Faction::getColor(regard->getRaceRegard(a))
				<< regard->getRaceRegard(a) << "^X ";
		}
	}
	for(a=0; a < DEITY_COUNT; a++) {
		if(regard->getDeityRegard(a)) {
			oStr << gConfig->getDeity(a)->getName() << ":"
				<< Faction::getColor(regard->getDeityRegard(a))
				<< regard->getDeityRegard(a) << "^X ";
		}
	}
	if(regard->getVampirismRegard()) {
		oStr << "Vampirism:"
			<< Faction::getColor(regard->getVampirismRegard())
			<< regard->getVampirismRegard() << "^X ";
	}
	oStr << regard->guildDisplay();
	oStr << regard->clanDisplay();
	if(regard->getOverallRegard())
		oStr << "Overall: " << regard->getOverallRegard();
	
	if(oStr.str() != "")
		viewer->printColor("    ^y%s:^x %s\n", type.c_str(), oStr.str().c_str());
}

//*********************************************************************
//						listFactions
//*********************************************************************

int listFactions(const Player* viewer, bool all) {
	if(!all)
		viewer->printColor("Type ^y*faction all^x to view all details.\n");
	viewer->printColor("^xFactions\n%-20s - %40s\n^b---------------------------------------------------------------\n", "Name", "DisplayName");

	std::map<bstring, Faction*>::iterator fIt;
	Faction* faction=0;

	for(fIt = gConfig->factions.begin() ; fIt != gConfig->factions.end() ; fIt++) {
		bstring tmp;
		faction = (*fIt).second;

		viewer->print("%-20s - %40s\n", faction->getName().c_str(), faction->getDisplayName().c_str());

		if(!all)
			continue;

		viewer->printColor(" Base Regard: %s%6d\n", (faction->getBaseRegard() >= 0 ? "^g" : "^R"), faction->getBaseRegard());

		showRegard(viewer, "Initial Regard", faction->getInitial());
		showRegard(viewer, "Max Regard", faction->getMax());
		showRegard(viewer, "Min Regard", faction->getMin());

		viewer->print("\n");
	}
	return(0);
}

//*********************************************************************
//						listFactions
//*********************************************************************

int listFactions(const Player* viewer, const Creature* target) {
	std::map<bstring, bstring> str;
	std::map<bstring, bstring>::const_iterator it;
	std::map<bstring, long>::const_iterator fIt;
	const Faction* faction=0;
	const Player* player = target->getAsConstPlayer();
	long	regard=0;
	long	i=0;

	if(viewer == target)
		viewer->print("Faction Standing");
	else {
		viewer->print("%s's Faction", target->getCName());
		const Monster* monster = target->getAsConstMonster();
		if(monster)
			viewer->printColor(", primeFaction: ^y%s", monster->getPrimeFaction().c_str());
	}
	viewer->printColor("\n^b----------------------------------------------------------------------\n");

	for(fIt = target->factions.begin() ; fIt != target->factions.end() ; fIt++) {
		faction = gConfig->getFaction((*fIt).first);
		regard = (*fIt).second;

		if(!faction)
			continue;
		// if showing a mob, show straight faction
		// if showing a player, show adjusted faction
		if(player) {
			regard += faction->getInitialRegard(player);
			if(faction->getParent() != "")
				regard += player->getFactionStanding(faction->getParent());
		}

		// Set left aligned
		std::ostringstream oStr;
		oStr.setf(std::ios::left, std::ios::adjustfield);
		oStr.imbue(std::locale(""));

		oStr << "   " << std::setw(35) << faction->getDisplayName() << Faction::getColor(regard)
			 << std::setw(13) << Faction::getNoun(regard) << "^x";

		// this doesnt make sense for mobs
		if(player)
			oStr << Faction::getBar(regard, true);

		if(viewer != target || target->isStaff()) {
			oStr << " ";
			if(player && i)
				oStr << "(Adj:" << regard << " Unadj:" << (regard - i) << ")";
			else
				oStr << "(" << regard << ")";
		}
		oStr << "\n";
		str[faction->getGroup()] += oStr.str();
	}

	for(it = str.begin() ; it != str.end() ; it++) {
		if((*it).first == "Other")
			continue;
		viewer->printColor("%s\n%s", (*it).first.c_str(), (*it).second.c_str());
	}
	if(str["Other"] != "")
		viewer->printColor("%s\n%s\n", "Other", str["Other"].c_str());
	return(0);
}

//*********************************************************************
//						dmShowFactions
//*********************************************************************

int dmShowFactions(Player *player, cmd* cmnd) {
	bool all = !strcmp(cmnd->str[1], "all");
	if(cmnd->num < 2 || all)
		listFactions(player, all);
	else {
		if(player->getClass() == BUILDER) {
			if(!player->canBuildMonsters())
				return(cmdNoAuth(player));
			if(!player->checkBuilder(player->getUniqueRoomParent())) {
				player->print("Error: room number not in any of your alotted ranges.\n");
				return(0);
			}
		}
		Creature* target=0;
		Monster *mTarget=0;

		target = player->getParent()->findCreature(player, cmnd);
		if(player->isCt()) {
			cmnd->str[1][0] = up(cmnd->str[1][0]);
			if(!target)
				target = gServer->findPlayer(cmnd->str[1]);
		}
		if(target) {
			if(player->getClass() == BUILDER) {
				mTarget = target->getAsMonster();
				if(mTarget && !player->checkBuilder(mTarget->info)) {
					player->print("Error: monster index not in any of your alotted ranges.\n");
					return(0);
				} else if(!mTarget) {
					player->print("Can't find '%s'\n", cmnd->str[1]);
					return(0);
				}
			}
			listFactions(player, target);
		} else
			player->print("Can't find '%s'\n", cmnd->str[1]);
	}
	return(0);
}

//*********************************************************************
//						cmdFactions
//*********************************************************************

int cmdFactions(Player* player, cmd* cmnd) {
	if(cmnd->num >= 2 && player->isStaff())
		return(dmShowFactions(player, cmnd));
	return(listFactions(player, player));
}

//*********************************************************************
//						getCutoff
//*********************************************************************

int Faction::getCutoff(int attitude) {
	switch(attitude) {
	case WORSHIP:
		return(WORSHIP_CUTOFF);
	case REGARD:
		return(REGARD_CUTOFF);
	case ADMIRATION:
		return(ADMIRATION_CUTOFF);
	case FAVORABLE:
		return(FAVORABLE_CUTOFF);
	case INDIFFERENT:
		return(INDIFFFERENT_CUTOFF);
	case DISAPPROVE:
		return(DISAPPROVE_CUTOFF);
	case DISFAVOR:
		return(DISFAVOR_CUTTOFF);
	case CONTEMPT:
		return(CONTEMPT_CUTOFF);
	default:
		return(0);
	}
}

//*********************************************************************
//						getAttitude
//*********************************************************************

int Faction::getAttitude(int regard) {
	if(regard >= WORSHIP_CUTOFF)
		return(WORSHIP);
	else if(regard >= REGARD_CUTOFF)
		return(REGARD);
	else if(regard >= ADMIRATION_CUTOFF)
		return(ADMIRATION);
	else if(regard >= FAVORABLE_CUTOFF)
		return(FAVORABLE);
	else if(regard >= INDIFFFERENT_CUTOFF)
		return(INDIFFERENT);
	else if(regard >= DISAPPROVE_CUTOFF)
		return(DISAPPROVE);
	else if(regard >= DISFAVOR_CUTTOFF)
		return(DISFAVOR);
	else if(regard >= CONTEMPT_CUTOFF)
		return(CONTEMPT);
	else
		return(MALICE);
}

//*********************************************************************
//						getBar
//*********************************************************************

bstring Faction::getBar(int regard, bool alwaysPad) {
	int attitude = getAttitude(regard);
	if(attitude == WORSHIP || attitude == MALICE) {
		if(alwaysPad)
			return("            ");
		return("");
	}

	int low = getCutoff(attitude);
	int num = (regard - low) * 10 / (getCutoff(attitude+1) - low);

	std::ostringstream oStr;
	oStr << "[^m";
	for(low = 0; low<num; low++)
		oStr << "x";
	for(; low<10; low++)
		oStr << " ";
	oStr << "^x]";
	return(oStr.str());
}

//*********************************************************************
//						getColor
//*********************************************************************

bstring Faction::getColor(int regard) {
	if(regard >= FAVORABLE_CUTOFF)
		return("^g");
	else if(regard <= DISAPPROVE_CUTOFF)
		return("^R");
	return("");
}

//*********************************************************************
//						getNoun
//*********************************************************************

bstring Faction::getNoun(int regard) {
	switch(getAttitude(regard)) {
	case WORSHIP:
		return("worshipped");
	case REGARD:
		return("high regard");
	case ADMIRATION:
		return("admiration");
	case FAVORABLE:
		return("favorable");
	case INDIFFERENT:
		return("indifferent");
	case DISAPPROVE:
		return("disapproving");
	case DISFAVOR:
		return("unfavorable");
	case CONTEMPT:
		return("contempt");
	case MALICE:
		return("malice");
	default:
		return("confusion");
	}
}

//*********************************************************************
//						getFactionMessage
//*********************************************************************
// Returns the faction standing of the current creature with regards to 'faction'

bstring Player::getFactionMessage(bstring factionStr) const {
	int regard = getFactionStanding(factionStr);
	std::ostringstream oStr;

	switch(Faction::getAttitude(regard)) {
	case Faction::WORSHIP:
		oStr << "worships you";
		break;
	case Faction::REGARD:
		oStr << "holds you in the highest regard";
		break;
	case Faction::ADMIRATION:
		oStr << "looks upon with you admiration";
		break;
	case Faction::FAVORABLE:
		oStr << "looks upon you favorably";
		break;
	case Faction::INDIFFERENT:
		oStr << "regards you indifferently";
		break;
	case Faction::DISAPPROVE:
		oStr << "disapproves of your presence";
		break;
	case Faction::DISFAVOR:
		oStr << "looks upon you unfavorably";
		break;
	case Faction::CONTEMPT:
		oStr << "looks upon you with contempt";
		break;
	case Faction::MALICE:
		oStr << "regards you with malice";
		break;
	default:
		oStr << "stares at you with confusion";
		break;
	}
	if(isDm())
		oStr << " (" << factionStr << ":" << Faction::getColor(regard) << regard << "^x)";

	return(oStr.str());
}

//*********************************************************************
//						getFactionStanding
//*********************************************************************
// Gets the faction standing of Creature with regards to 'faction'

int Player::getFactionStanding(bstring factionStr) const {
	int regard = 0;
	std::map<bstring, long>::const_iterator it = factions.find(factionStr);

	if(it != factions.end())
		regard += (*it).second;

	const Faction* faction = gConfig->getFaction(factionStr);
	if(faction) {
		regard += faction->getInitialRegard(this);
		if(faction->getParent() != "")
			regard += getFactionStanding(faction->getParent());
	}

	return(regard);
}

//*********************************************************************
//						adjustFactionStanding
//*********************************************************************
// Adjust the killer's faction standing for killing the victim

void Player::adjustFactionStanding(const std::map<bstring, long>& factionList) {
	std::map<bstring, long>::const_iterator fIt;
	std::ostringstream oStr;
	const Faction *faction=0;
	long	regard=0, current=0, limit=0;

	for(fIt = factionList.begin() ; fIt != factionList.end() ; fIt++) {
		faction = gConfig->getFaction((*fIt).first);
		regard = (*fIt).second;

		if(!regard || !faction)
			continue;

		current = factions[faction->getName()];

		// this is where adjusted faction comes into play;
		// prevent them from going out-of-bounds
		limit = faction->getUpperLimit(this);
		if(current - regard > limit)
			regard = current - limit;
		limit = faction->getLowerLimit(this);
		if(current - regard < limit)
			regard = current - limit;

		// it was adjusted to 0, meaning we can't move any more
		if(!regard)
			continue;
		if(faction->alwaysHates(this) && regard <= 0)
			continue;

		oStr << (regard > 0 ? "^R" : "^c")
			<< "Your faction standing with " << faction->getDisplayName()
			<< (faction->isParent() ? " and its subfactions" : "")
			<< (regard > 0 ? " has gotten worse." : " has improved.");

		if(isDm())
			oStr << " (" << abs(regard) << ")";

		oStr << "\n";
		factions[faction->getName()] -= regard;
	}

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

//*********************************************************************
//						worshipSocial
//*********************************************************************

void Faction::worshipSocial(Monster *monster) {
	if(monster->getPrimeFaction() == "")
		return;
	// only certain monster types perform this action
	if(!monType::isIntelligent(monster->getType()) && !monster->getRace())
		return;
	if(monster->inCombat())
		return;
	const Faction *faction = gConfig->getFaction(monster->getPrimeFaction());
	if(!faction)
		return;
	bstring social = faction->getSocial();
	if(social == "")
		return;

	// we've made sure everything is ok; let's continue
	// with the actual work
	cmd		cmnd;

	strcpy(cmnd.str[0], social.c_str());
	cmnd.num = 2;
	cmnd.val[1] = 1;
	for(Player* player : monster->getRoomParent()->players) {
		if(	mrand(1,100)>2 ||
			!player ||
			player->flagIsSet(P_UNCONSCIOUS) ||
			!monster->canSee(player) ||
			monster->isEnemy(player) ||
			player->isEffected("petrification") ||
			player->inCombat() ||
			player->isStaff()
		)
			continue;

		if(getAttitude(player->getFactionStanding(monster->getPrimeFaction())) < WORSHIP)
			continue;

		strcpy(cmnd.str[1], player->getCName());
		cmdProcess(monster, &cmnd);
	}
}

//*********************************************************************
//						willAggro
//*********************************************************************

bool Faction::willAggro(const Player* player, bstring faction) {
	if(faction == "")
		return(false);
	int attitude = getAttitude(player->getFactionStanding(faction));
	if(attitude <= MALICE)
		return(true);
	if(attitude == CONTEMPT && mrand(1,100) <= 10)
		return(true);
	return(false);
}

//*********************************************************************
//						willSpeakWith
//*********************************************************************

bool Faction::willSpeakWith(const Player* player, bstring faction) {
	if(faction == "")
		return(true);
	return(getAttitude(player->getFactionStanding(faction)) > CONTEMPT);
}

//*********************************************************************
//						willDoBusinessWith
//*********************************************************************

bool Faction::willDoBusinessWith(const Player* player, bstring faction) {
	if(faction == "")
		return(true);
	return(getAttitude(player->getFactionStanding(faction)) > DISFAVOR);
}

//*********************************************************************
//						willBeneCast
//*********************************************************************

bool Faction::willBeneCast(const Player* player, bstring faction) {
	if(faction == "")
		return(true);
	return(getAttitude(player->getFactionStanding(faction)) >= INDIFFERENT);
}

//*********************************************************************
//						willLetThrough
//*********************************************************************

bool Faction::willLetThrough(const Player* player, bstring faction) {
	if(faction == "")
		return(false);
	return(getAttitude(player->getFactionStanding(faction)) >= FAVORABLE);
}

//*********************************************************************
//						adjustPrice
//*********************************************************************

Money Faction::adjustPrice(const Player* player, bstring faction, Money money, bool sell) {
	if(faction == "")
		return(money);
	int attitude = getAttitude(player->getFactionStanding(faction));

	if(attitude <= DISAPPROVE) {
		if(sell)
			money.set(money[GOLD] * 2, GOLD);
		else
			money.set(money[GOLD] / 2, GOLD);
	} else if(attitude >= FAVORABLE && attitude < REGARD) {
		if(sell)
			money.sub(money[GOLD] / 20, GOLD);
		else
			money.add(money[GOLD] / 20, GOLD);
	} else if(attitude >= REGARD) {
		if(sell)
			money.sub(money[GOLD] / 10, GOLD);
		else
			money.add(money[GOLD] / 10, GOLD);
	}

	return(money);
}


//*********************************************************************
//						canPledgeTo
//*********************************************************************

bool Faction::canPledgeTo(const Player* player, bstring faction) {
	if(faction == "")
		return(true);
	return(getAttitude(player->getFactionStanding(faction)) >= INDIFFERENT);
}


// Clears factions
void Config::clearFactionList() {
	std::map<bstring, Faction*>::iterator fIt;
	Faction* faction;

	for(fIt = factions.begin() ; fIt != factions.end() ; fIt++) {
		faction = (*fIt).second;
		delete faction;
		//factions.erase(fIt);
	}
	factions.clear();
}


bool Config::loadFactions() {
	xmlDocPtr	xmlDoc;
	//GuildCreation * curCreation;
	xmlNodePtr	cur;
	char		filename[80];

	// build an XML tree from the file
	sprintf(filename, "%s/factions.xml", Path::Game);

	xmlDoc = xml::loadFile(filename, "Factions");
	if(xmlDoc == NULL)
		return(false);

	cur = xmlDocGetRootElement(xmlDoc);

	// First level we expect a faction
	cur = cur->children;
	while(cur && xmlIsBlankNode(cur))
		cur = cur->next;

	if(cur == 0) {
		xmlFreeDoc(xmlDoc);
		xmlCleanupParser();
		return(false);
	}

	clearFactionList();
	Faction* faction;
	while(cur != NULL) {
		if(NODE_NAME(cur, "Faction")) {
			faction = new Faction;
			faction->load(cur);
			factions[faction->getName()] = faction;
		}
		cur = cur->next;
	}
	xmlFreeDoc(xmlDoc);
	xmlCleanupParser();

	std::map<bstring, Faction*>::const_iterator it, fIt;

	for(it = factions.begin(); it != factions.end(); it++) {
		faction = (*it).second;

		if(faction->getParent() != "") {
			fIt = factions.find(faction->getParent());

			if(fIt == factions.end()) {
				faction->setParent("");
			} else {
				(*fIt).second->setIsParent(true);
			}
		}
	}
	return(true);
}