roh/conf/area/
roh/game/talk/
roh/help/
roh/monsters/ocean/
roh/objects/ocean/
roh/player/
roh/rooms/area/1/
roh/rooms/misc/
roh/rooms/ocean/
roh/src-2.44b/
/*
 * creatures.cpp
 *   Functions that work on creatures etc
 *   ____            _
 *  |  _ \ ___  __ _| |_ __ ___  ___
 *  | |_) / _ \/ _` | | '_ ` _ \/ __|
 *  |  _ <  __/ (_| | | | | | | \__ \
 *  |_| \_\___|\__,_|_|_| |_| |_|___/
 *
 * 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-2009 Jason Mitchell, Randi Mitchell
 * 	   Contributions by Tim Callahan, Jonathan Hseu
 *  Based on Mordor (C) Brooke Paul, Brett J. Vickers, John P. Freeman
 *
 */
// Mud Includes
#include "mud.h"
#include "version.h"
#include "commands.h"
#include "effects.h"
#include "specials.h"
#include "calendar.h"
#include "quests.h"
#include "guilds.h"
#include "property.h"
// C++ includes
#include <sstream>
#include <iomanip>
#include <locale>


//*********************************************************************
//						Damage
//*********************************************************************

Damage::Damage() {
	reset();
}

int Damage::get() const { return(damage); }
int Damage::getBonus() const { return(bonus); }
int Damage::getDrain() const { return(drain); }
int Damage::getReflected() const { return(reflected); }
int Damage::getDoubleReflected() const { return(doubleReflected); }
int Damage::getPhysicalReflected() const { return(physicalReflected); }
ReflectedDamageType Damage::getPhysicalReflectedType() const { return(physicalReflectedType); }
int Damage::getPhysicalBonusReflected() const { return(physicalBonusReflected); }

void Damage::add(int d) { damage += d; }
void Damage::set(int d) { damage = d; }
void Damage::includeBonus(int fraction) {
	if(!fraction)
		fraction = 1;
	damage += bonus / fraction;
	physicalReflected += physicalBonusReflected / fraction;
}
void Damage::setBonus(int b) { bonus = b; }
void Damage::setDrain(int d) { drain = d; }
void Damage::setBonus(Damage dmg) {
	setBonus(dmg.get());
	physicalBonusReflected = dmg.getPhysicalReflected();
}
void Damage::setReflected(int r) { reflected = r; }
void Damage::setDoubleReflected(int r) { doubleReflected = r; }
void Damage::setPhysicalReflected(int r) { physicalReflected = r; }
void Damage::setPhysicalReflectedType(ReflectedDamageType type) { physicalReflectedType = type; }

//*********************************************************************
//						reset
//*********************************************************************

void Damage::reset() {
	damage = bonus = drain = reflected = doubleReflected = physicalReflected = physicalBonusReflected = 0;
	physicalReflectedType = REFLECTED_NONE;
}

//*********************************************************************
//						StringStatistic
//*********************************************************************

StringStatistic::StringStatistic() {
	reset();
}

void StringStatistic::save(xmlNodePtr rootNode, bstring nodeName) const {
	if(!value && name == "")
		return;
	xmlNodePtr curNode = xml::newStringChild(rootNode, nodeName);

	xml::saveNonZeroNum(curNode, "Value", value);
	xml::saveNonNullString(curNode, "Name", name);
}

void StringStatistic::load(xmlNodePtr curNode) {
	xmlNodePtr childNode = curNode->children;

	while(childNode) {
		if(NODE_NAME(childNode, "Value")) xml::copyToNum(value, childNode);
		else if(NODE_NAME(childNode, "Name")) xml::copyToBString(name, childNode);
		childNode = childNode->next;
	}
}

void StringStatistic::update(unsigned long num, bstring with) {
	if(num > value) {
		value = num;
		name = stripColor(with);
	}
}

void StringStatistic::reset() {
	value = 0;
	name = "";
}

//*********************************************************************
//						Statistics
//*********************************************************************

Statistics::Statistics() {
	track = true;
	numPkWon = numPkIn = 0;
	reset();
}

void Statistics::reset() {
	numSwings = numHits = numMisses = numFumbles = numDodges =
		numCriticals = numTimesHit = numTimesMissed = numTimesFled =
		numCasts = numOffensiveCasts = numHealingCasts = numKills =
		numDeaths = numThefts = numAttemptedThefts = numSaves =
		numAttemptedSaves = numRecalls = numLagouts = numWandsUsed =
		numPotionsDrank = numItemsCrafted = numFishCaught = numCombosOpened =
		mostGroup = numPkIn = numPkWon = 0;
	mostMonster.reset();
	mostAttackDamage.reset();
	mostMagicDamage.reset();
	long t = time(0);
	start = ctime(&t);
	start = start.trim();
}

void Statistics::display(const Player* viewer, bool death) {
	std::ostringstream oStr;
	// set left aligned
	oStr.setf(std::ios::left, std::ios::adjustfield);
	oStr.imbue(std::locale(""));

	if(death) {
		// if death = true, player will always be the owner
		oStr << "^WGeneral player statistics:^x\n"
			 << "  Level:            ^C" << parent->getLevel() << "^x\n"
			 << "  Total Experience: ^C" << parent->getExperience() << "^x\n"
			 << "  Time Played:      ^C" << parent->getTimePlayed() << "^x\n"
			 << "\n";
	}

	oStr << "Tracking statistics since: ^C" << start << "\n";
	if(	numSwings ||
		numDodges ||
		numTimesHit ||
		numTimesMissed ||
		numDeaths ||
		numKills ||
		numPkIn
	)
		oStr << "^WCombat^x\n";
	if(numSwings) {
		oStr << "  Swings:       ^C" << numSwings << "^x\n";
		if(numHits)
			oStr << "  Hits:         ^C" << numHits << " (" << (numHits * 100 / numSwings) << "%)^x\n";
		if(numMisses)
			oStr << "  Misses:       ^C" << numMisses << " (" << (numMisses * 100 / numSwings) << "%)^x\n";
		if(numFumbles)
			oStr << "  Fumbles:      ^C" << numFumbles << " (" << (numFumbles * 100 / numSwings) << "%)^x\n";
		if(numCriticals)
			oStr << "  Criticals:    ^C" << numCriticals << " (" << (numCriticals * 100 / numSwings) << "%)^x\n";
	}
	if(numDodges)
		oStr << "  Dodges:       ^C" << numDodges << "^x\n";
	if(numTimesHit)
		oStr << "  Times Hit:    ^C" << numTimesHit << "^x\n";
	if(numTimesMissed)
		oStr << "  Times Missed: ^C" << numTimesMissed << "^x\n";
	// Don't want to see this info after all
	//if(numTimesFled)
	//	oStr << "  Times Fled:   ^C" << numTimesFled << "^x\n";
	if(numDeaths)
		oStr << "  Deaths:       ^C" << numDeaths << "^x\n";
	if(numKills)
		oStr << "  Kills:        ^C" << numKills << "^x\n";
	if(numPkIn)
		oStr << "  Player kills: ^C" << numPkWon << "/" << numPkIn << " (" << (numPkWon * 100 / numPkIn) << "%)^x\n";


	if(	numCasts ||
		numOffensiveCasts ||
		numHealingCasts ||
		numWandsUsed ||
		numPotionsDrank
	)
		oStr << "\n^WMagic^x\n";
	if(numHealingCasts)
		oStr << "  Spells cast:  ^C" << numCasts << "^x\n";
	if(numCasts) {
		if(numOffensiveCasts)
			oStr << "     Offensive Spells: ^C" << numOffensiveCasts << " (" << (numOffensiveCasts * 100 / numCasts) << "%)^x\n";
		if(numHealingCasts)
			oStr << "     Healing Spells:   ^C" << numHealingCasts << " (" << (numHealingCasts * 100 / numCasts) << "%)^x\n";
	}
	if(numWandsUsed)
		oStr << "  Wands used:   ^C" << numWandsUsed << "^x\n";
	if(numPotionsDrank)
		oStr << "  Potions used: ^C" << numPotionsDrank << "^x\n";


	if(	mostGroup ||
		mostMonster.value ||
		mostAttackDamage.value ||
		mostMagicDamage.value
	)
		oStr << "\n^WMost / Largest^x\n";
	if(mostGroup)
		oStr << "  Largest group:             ^C" << mostGroup << "^x\n";
	if(mostMonster.value)
		oStr << "  Toughest monster killed:   ^C" << mostMonster.name << "^x\n";
	if(mostAttackDamage.value)
		oStr << "  Most damage in one attack: ^C" << mostAttackDamage.value << " with " << mostAttackDamage.name << "^x\n";
	if(mostMagicDamage.value)
		oStr << "  Most damage in one spell:  ^C" << mostMagicDamage.value << " with " << mostMagicDamage.name << "^x\n";


	int rooms = parent->numDiscoveredRooms();
	if(	(numThefts && numAttemptedThefts) ||
		(numSaves && numAttemptedSaves) ||
		numRecalls ||
		numLagouts ||
		numFishCaught ||
		numItemsCrafted ||
		numCombosOpened ||
		rooms
	)
		oStr << "\n^WOther^x\n";
	if(numThefts && numAttemptedThefts)
		oStr << "  Items stolen:                ^C" << numThefts << "/" << numAttemptedThefts << " (" << (numThefts * 100 / numAttemptedThefts) << "%)^x\n";
	if(numSaves && numAttemptedSaves)
		oStr << "  Saving throws made:          ^C" << numSaves << "/" << numAttemptedSaves << " (" << (numSaves * 100 / numAttemptedSaves) << "%)^x\n";
	if(numRecalls)
		oStr << "  Hazies/word-of-recalls used: ^C" << numRecalls << "^x\n";
	if(numLagouts)
		oStr << "  Lagouts:                     ^C" << numLagouts << "^x\n";
	if(numFishCaught)
		oStr << "  Fish caught:                 ^C" << numFishCaught << "^x\n";
	if(numItemsCrafted)
		oStr << "  Items crafted:               ^C" << numItemsCrafted << "^x\n";
	if(numCombosOpened)
		oStr << "  Combinations opened:         ^C" << numCombosOpened << "^x\n";
	if(rooms)
		oStr << "  Special rooms discovered:    ^C" << rooms << "^x\n";

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

unsigned long Statistics::calcToughness(const Monster* monster) {
	unsigned long t = monster->hp.getMax();
	t += monster->getAttackPower();
	t += monster->getWeaponSkill();
	t += monster->getDefenseSkill();
	// level is weighted
	t += monster->getLevel() * 2;
	// only a percentage of their mana counts
	t += (monster->mp.getMax() * monster->getCastChance() / 100);
	return(t);
}

bstring Statistics::damageWith(const Player* player, const Object* weapon) {
	if(weapon)
		return(weapon->getObjStr(NULL, INV | MAG, 1));
	return((bstring)"your " + player->getUnarmedWeaponSkill() + "s");
}

unsigned long Statistics::pkDemographics() const {
	if(numPkIn == numPkWon)
		return(0);
	return(pkRank());
}

bstring Statistics::getTime() {
	return(start);
}

void Statistics::save(xmlNodePtr rootNode, bstring nodeName) const {
	xmlNodePtr curNode = xml::newStringChild(rootNode, nodeName);

	xml::newNumChild(curNode, "Track", track);
	xml::saveNonNullString(curNode, "Start", start);

	xml::saveNonZeroNum(curNode, "NumSwings", numSwings);
	xml::saveNonZeroNum(curNode, "NumHits", numHits);
	xml::saveNonZeroNum(curNode, "NumMisses", numMisses);
	xml::saveNonZeroNum(curNode, "NumFumbles", numFumbles);
	xml::saveNonZeroNum(curNode, "NumDodges", numDodges);
	xml::saveNonZeroNum(curNode, "NumCriticals", numCriticals);
	xml::saveNonZeroNum(curNode, "NumTimesHit", numTimesHit);
	xml::saveNonZeroNum(curNode, "NumTimesMissed", numTimesMissed);
	xml::saveNonZeroNum(curNode, "NumTimesFled", numTimesFled);
	xml::saveNonZeroNum(curNode, "NumPkIn", numPkIn);
	xml::saveNonZeroNum(curNode, "NumPkWon", numPkWon);
	xml::saveNonZeroNum(curNode, "NumCasts", numCasts);
	xml::saveNonZeroNum(curNode, "NumOffensiveCasts", numOffensiveCasts);
	xml::saveNonZeroNum(curNode, "NumHealingCasts", numHealingCasts);
	xml::saveNonZeroNum(curNode, "NumKills", numKills);
	xml::saveNonZeroNum(curNode, "NumDeaths", numDeaths);
	xml::saveNonZeroNum(curNode, "NumThefts", numThefts);
	xml::saveNonZeroNum(curNode, "NumAttemptedThefts", numAttemptedThefts);
	xml::saveNonZeroNum(curNode, "NumSaves", numSaves);
	xml::saveNonZeroNum(curNode, "NumAttemptedSaves", numAttemptedSaves);
	xml::saveNonZeroNum(curNode, "NumRecalls", numRecalls);
	xml::saveNonZeroNum(curNode, "NumLagouts", numLagouts);
	xml::saveNonZeroNum(curNode, "NumWandsUsed", numWandsUsed);
	xml::saveNonZeroNum(curNode, "NumPotionsDrank", numPotionsDrank);
	xml::saveNonZeroNum(curNode, "NumFishCaught", numFishCaught);
	xml::saveNonZeroNum(curNode, "NumItemsCrafted", numItemsCrafted);
	xml::saveNonZeroNum(curNode, "NumCombosOpened", numCombosOpened);
	xml::saveNonZeroNum(curNode, "MostGroup", mostGroup);
	mostMonster.save(curNode, "MostMonster");
	mostAttackDamage.save(curNode, "MostAttackDamage");
	mostMagicDamage.save(curNode, "MostMagicDamage");
}

void Statistics::load(xmlNodePtr curNode) {
	xmlNodePtr childNode = curNode->children;

	while(childNode) {
			 if(NODE_NAME(childNode, "Track")) xml::copyToBool(track, childNode);
		else if(NODE_NAME(childNode, "Start")) xml::copyToBString(start, childNode);
		else if(NODE_NAME(childNode, "NumSwings")) xml::copyToNum(numSwings, childNode);
		else if(NODE_NAME(childNode, "NumHits")) xml::copyToNum(numHits, childNode);
		else if(NODE_NAME(childNode, "NumMisses")) xml::copyToNum(numMisses, childNode);
		else if(NODE_NAME(childNode, "NumFumbles")) xml::copyToNum(numFumbles, childNode);
		else if(NODE_NAME(childNode, "NumDodges")) xml::copyToNum(numDodges, childNode);
		else if(NODE_NAME(childNode, "NumCriticals")) xml::copyToNum(numCriticals, childNode);
		else if(NODE_NAME(childNode, "NumTimesHit")) xml::copyToNum(numTimesHit, childNode);
		else if(NODE_NAME(childNode, "NumTimesMissed")) xml::copyToNum(numTimesMissed, childNode);
		else if(NODE_NAME(childNode, "NumTimesFled")) xml::copyToNum(numTimesFled, childNode);
		else if(NODE_NAME(childNode, "NumPkIn")) xml::copyToNum(numPkIn, childNode);
		else if(NODE_NAME(childNode, "NumPkWon")) xml::copyToNum(numPkWon, childNode);
		else if(NODE_NAME(childNode, "NumCasts")) xml::copyToNum(numCasts, childNode);
		else if(NODE_NAME(childNode, "NumOffensiveCasts")) xml::copyToNum(numOffensiveCasts, childNode);
		else if(NODE_NAME(childNode, "NumHealingCasts")) xml::copyToNum(numHealingCasts, childNode);
		else if(NODE_NAME(childNode, "NumKills")) xml::copyToNum(numKills, childNode);
		else if(NODE_NAME(childNode, "NumDeaths")) xml::copyToNum(numDeaths, childNode);
		else if(NODE_NAME(childNode, "NumThefts")) xml::copyToNum(numThefts, childNode);
		else if(NODE_NAME(childNode, "NumAttemptedThefts")) xml::copyToNum(numAttemptedThefts, childNode);
		else if(NODE_NAME(childNode, "NumSaves")) xml::copyToNum(numSaves, childNode);
		else if(NODE_NAME(childNode, "NumAttemptedSaves")) xml::copyToNum(numAttemptedSaves, childNode);
		else if(NODE_NAME(childNode, "NumRecalls")) xml::copyToNum(numRecalls, childNode);
		else if(NODE_NAME(childNode, "NumLagouts")) xml::copyToNum(numLagouts, childNode);
		else if(NODE_NAME(childNode, "NumWandsUsed")) xml::copyToNum(numWandsUsed, childNode);
		else if(NODE_NAME(childNode, "NumPotionsDrank")) xml::copyToNum(numPotionsDrank, childNode);
		else if(NODE_NAME(childNode, "NumFishCaught")) xml::copyToNum(numFishCaught, childNode);
		else if(NODE_NAME(childNode, "NumItemsCrafted")) xml::copyToNum(numItemsCrafted, childNode);
		else if(NODE_NAME(childNode, "NumCombosOpened")) xml::copyToNum(numCombosOpened, childNode);
		else if(NODE_NAME(childNode, "MostGroup")) xml::copyToNum(mostGroup, childNode);
		else if(NODE_NAME(childNode, "MostMonster")) mostMonster.load(childNode);
		else if(NODE_NAME(childNode, "MostAttackDamage")) mostAttackDamage.load(childNode);
		else if(NODE_NAME(childNode, "MostMagicDamage")) mostMagicDamage.load(childNode);
		childNode = childNode->next;
	}
}

void Statistics::swing() { if(track) numSwings++; }
void Statistics::hit() { if(track) numHits++; }
void Statistics::miss() { if(track) numMisses++; }
void Statistics::fumble() { if(track) numFumbles++; }
void Statistics::dodge() { if(track) numDodges++; }
void Statistics::critical() { if(track) numCriticals++; }
void Statistics::wasHit() { if(track) numTimesHit++; }
void Statistics::wasMissed() { if(track) numTimesMissed++; }
void Statistics::flee() { if(track) numTimesFled++; }
// because these two stats are older, they're always tracked
void Statistics::winPk() { numPkIn++; numPkWon++; }
void Statistics::losePk() { numPkIn++; }
void Statistics::cast() { if(track) numCasts++; }
void Statistics::offensiveCast() { if(track) numOffensiveCasts++; }
void Statistics::healingCast() { if(track) numHealingCasts++; }
void Statistics::kill() { if(track) numKills++; }
void Statistics::die() { if(track) numDeaths++; }
void Statistics::steal() { if(track) numThefts++; }
void Statistics::attemptSteal() { if(track) numAttemptedThefts++; }
void Statistics::save() { if(track) numSaves++; }
void Statistics::attemptSave() { if(track) numAttemptedSaves++; }
void Statistics::recall() { if(track) numRecalls++; }
void Statistics::lagout() { if(track) numLagouts++; }
void Statistics::wand() { if(track) numWandsUsed++; }
void Statistics::potion() { if(track) numPotionsDrank++; }
void Statistics::fish() { if(track) numFishCaught++; }
void Statistics::craft() { if(track) numItemsCrafted++; }
void Statistics::combo() { if(track) numCombosOpened++; }
void Statistics::group(unsigned long num) { if(track) mostGroup = MAX(num, mostGroup); }
void Statistics::monster(const Monster* monster) {
	if(!track || monster->isPet())
		return;
	mostMonster.update(calcToughness(monster), monster->name);
}
void Statistics::attackDamage(unsigned long num, bstring with) {
	if(track) mostAttackDamage.update(num, with);
}
void Statistics::magicDamage(unsigned long num, bstring with) {
	if(track) mostMagicDamage.update(num, with);
}
void Statistics::setParent(Player* player) { parent = player; }

//*********************************************************************
//						pkRank
//*********************************************************************
// This function returns the rank of the player based on how many
// pkills they has been in, and how many they have won

unsigned long Statistics::pkRank() const {
	if(!numPkWon || !numPkIn)
		return(0);
	return(numPkWon * 100 / numPkIn);
}

unsigned long Statistics::getPkin() const { return(numPkIn); }
unsigned long Statistics::getPkwon() const { return(numPkWon); }
// remove when all players are up to 2.42i
void Statistics::setPkin(unsigned long p) { numPkIn = p; }
void Statistics::setPkwon(unsigned long p) { numPkWon = p; }

//*********************************************************************
//						creature get
//*********************************************************************

Location Creature::getLocation() {
	Location l;

	if(parent_rom)
		l.room = room;
	if(area_room)
		l.mapmarker = area_room->mapmarker;

	return(l);
}

unsigned short Creature::getClass() const { return(cClass); }
unsigned short Creature::getLevel() const { return(level); }
short Creature::getAlignment() const { return(alignment); }
unsigned int Creature::getArmor() const { return(armor); }
unsigned long Creature::getExperience() const { return(experience); }
unsigned short Creature::getClan() const { return(clan); }
mType Creature::getType() const { return(type); }
unsigned short Creature::getRace() const { return(race); }
unsigned short Creature::getDeity() const { return(deity); }
Size Creature::getSize() const { return(size); }
unsigned int Creature::getAttackPower() const { return(attackPower); }
bstring Creature::getDescription() const { return(description); }
bstring Creature::getVersion() const { return(version); }
unsigned short Creature::getPoisonDuration() const { return(poison_dur); }
unsigned short Creature::getPoisonDamage() const { return(poison_dmg); }
Sex Creature::getSex() const {
	if(isPlayer()) {
		if(flagIsSet(P_SEXLESS))
			return(SEX_NONE);
		if(flagIsSet(P_MALE))
			return(SEX_MALE);
		return(SEX_FEMALE);
	} else {
		if(flagIsSet(M_SEXLESS))
			return(SEX_NONE);
		if(flagIsSet(M_MALE))
			return(SEX_MALE);
		return(SEX_FEMALE);
	}
}
unsigned long Creature::getRealm(Realm r) const { return(realm[r-1]); }
bstring Creature::getPoisonedBy() const { return(poisonedBy); }
bool Creature::inJail() const {
	if(isStaff())
		return(false);
	if(!parent_rom)
		return(false);
	return(parent_rom->flagIsSet(R_JAIL));
}

//*********************************************************************
//						creature set
//*********************************************************************

void Creature::addExperience(unsigned long e) { setExperience(experience + e); }
void Creature::subExperience(unsigned long e) { setExperience(e > experience ? 0 : experience - e); }
void Creature::setExperience(unsigned long e) { experience = MIN(2100000000, e); }
void Creature::setClass(unsigned short c) {
	c = MIN(CLASS_COUNT-1, c);

	if(cClass == VAMPIRE && c != VAMPIRE)
		removeEffect("vampirism");
	else if(cClass == WEREWOLF && c != WEREWOLF)
		removeEffect("lycanthropy");

	if(cClass != VAMPIRE && c == VAMPIRE) {
		if(!isEffected("vampirism")) {
			addPermEffect("vampirism");
			if(isPlayer())
				getPlayer()->makeVampire();
		}
	} else if(cClass != WEREWOLF && c == WEREWOLF) {
		if(!isEffected("lycanthropy")) {
			addPermEffect("lycanthropy");
			if(isPlayer())
				getPlayer()->makeWerewolf();
		}
	}

	cClass = c;
}
void Creature::setClan(unsigned short c) { clan = c; }
void Creature::setLevel(unsigned short l, bool isDm) { level = MAX(1, MIN(l, isDm ? 127 : MAXALVL)); }
void Creature::setAlignment(short a) { alignment = MAX(-1000, MIN(1000, a)); }
void Creature::subAlignment(unsigned short a) { setAlignment(alignment - a); }
void Creature::setArmor(unsigned int a) { armor = MAX(MIN(a, MAX_ARMOR), 0); }
void Creature::setAttackPower(unsigned int a) { attackPower = MIN(1500, a); }
void Creature::setDeity(unsigned short d) { deity = MIN(d, DEITY_COUNT-1); }
void Creature::setRace(unsigned short r) { race = MIN(gConfig->raceCount()-1, r); }
void Creature::setSize(Size s) { size = MAX(NO_SIZE, MIN(MAX_SIZE, s)); }
void Creature::setType(unsigned short t) { type = (mType)MIN(MAX_MOB_TYPES-1, t); }
void Creature::setType(mType t) { type = t; }
void Creature::setDescription(const bstring& desc) {
	description = desc;
	if(isMonster())
		description.Replace("*CR*", "\n");
}
void Creature::setVersion(bstring v) { version = v == "" ? VERSION : v; }
void Creature::setVersion(xmlNodePtr rootNode) { xml::copyPropToBString(version, rootNode, "Version"); }
void Creature::setPoisonDuration(unsigned short d) { poison_dur = d; }
void Creature::setPoisonDamage(unsigned short d) { poison_dmg = d; }
void Creature::setSex(Sex sex) {
	if(isPlayer()) {
		if(sex == SEX_FEMALE) {
			clearFlag(P_SEXLESS);
			clearFlag(P_MALE);
		} else if(sex == SEX_MALE) {
			clearFlag(P_SEXLESS);
			setFlag(P_MALE);
		} else {
			setFlag(P_SEXLESS);
			clearFlag(P_MALE);
		}
	} else {
		if(sex == SEX_FEMALE) {
			clearFlag(M_SEXLESS);
			clearFlag(M_MALE);
		} else if(sex == SEX_MALE) {
			clearFlag(M_SEXLESS);
			setFlag(M_MALE);
		} else {
			setFlag(M_SEXLESS);
			clearFlag(M_MALE);
		}
	}
}
void Creature::setDeathType(DeathType d) { deathtype = d; }
void Creature::setRealm(unsigned long num, Realm r) { realm[r-1] = MIN(10000000, num); }
void Creature::addRealm(unsigned long num, Realm r) { setRealm(getRealm(r) + num, r); }
void Creature::subRealm(unsigned long num, Realm r) { setRealm(num > getRealm(r) ? 0 : getRealm(r) - num, r); }
void Creature::setPoisonedBy(const bstring& p) { poisonedBy = p; }

//*********************************************************************
//						monster get
//*********************************************************************

unsigned short Monster::getMobTrade() const { return(mobTrade); }
int Monster::getSkillLevel() const { return(skillLevel); }
unsigned int Monster::getMaxLevel() const { return(maxLevel); }
unsigned short Monster::getNumWander() const { return(numwander); }
unsigned short Monster::getLoadAggro() const { return(loadAggro); }
unsigned short Monster::getUpdateAggro() const { return(updateAggro); }
unsigned short Monster::getCastChance() const { return(cast); }
unsigned short Monster::getMagicResistance() const { return(magicResistance); }
bstring Monster::getPrimeFaction() const { return(primeFaction); }
bstring Monster::getTalk() const { return(talk); }

//*********************************************************************
//						monster set
//*********************************************************************

void Monster::setMaxLevel(unsigned short l) { maxLevel = MAX(1, MIN(l, MAXALVL)); }
void Monster::setCastChance(unsigned short c) { cast = MAX(0, MIN(c, 100)); }
void Monster::setMagicResistance(unsigned short m) { magicResistance = MAX(0, MIN(100, m)); }
void Monster::setLoadAggro(unsigned short a) { loadAggro = MAX(0, MIN(a, 99)); }
void Monster::setUpdateAggro(unsigned short a) { updateAggro = MAX(1, MIN(a, 99)); }
void Monster::setNumWander(unsigned short n) { numwander = MAX(0, MIN(6, n)); }
void Monster::setSkillLevel(int l) { skillLevel = MAX(0, MIN(100, l)); }
void Monster::setMobTrade(unsigned short t) { mobTrade = MAX(0, MIN(MOBTRADE_COUNT-1, t)); }
void Monster::setPrimeFaction(bstring f) { primeFaction = f; }
void Monster::setTalk(bstring t) { talk = t; talk.Replace("*CR*", "\n"); }

//*********************************************************************
//						player get
//*********************************************************************

unsigned short Player::getSecondClass() const { return(cClass2); }
unsigned short Player::getGuild() const { return(guild); }
unsigned short Player::getGuildRank() const { return(guildRank); }
unsigned short Player::getActualLevel() const { return(actual_level); }
unsigned short Player::getNegativeLevels() const { return(negativeLevels); }
unsigned short Player::getWimpy() const { return(wimpy); }
unsigned short Player::getTickDamage() const { return(tickDmg); }
unsigned short Player::getWarnings() const { return(warnings); }
unsigned long Player::getLostExperience() const { return(lostExperience); }
unsigned short Player::getPkin() const { return(pkin); }
unsigned short Player::getPkwon() const { return(pkwon); }
short Player::getLuck() const { return(luck); }
unsigned short Player::getWeaponTrains() const { return(weaponTrains); }
long Player::getLastLogin() const { return(lastLogin); }
long Player::getLastInterest() const { return(lastInterest); }
bstring Player::getLastPassword() const { return(lastPassword); }
bstring Player::getAfflictedBy() const { return(afflictedBy); }
bstring Player::getLastCommunicate() const { return(lastCommunicate); }
bstring Player::getLastCommand() const { return(lastCommand); }
bstring Player::getSurname() const { return(surname); }
bstring Player::getForum() const { return(forum); }
long Player::getCreated() const { return(created); }
bstring Player::getCreatedStr() const {
	bstring str;
	if(created) {
		str = ctime(&created);
		str.trim();
	} else
		str = oldCreated;
	return(str);
}
Monster* Player::getAlias() const { return(alias_crt); }
cDay* Player::getBirthday() const { return(birthday); }
bstring Player::getAnchorAlias(int i) const { return(anchor[i] ? anchor[i]->getAlias() : ""); }
bstring Player::getAnchorRoomName(int i) const { return(anchor[i] ? anchor[i]->getRoomName() : ""); }
const Anchor* Player::getAnchor(int i) const { return(anchor[i]); }
bool Player::hasAnchor(int i) const { return(!!anchor[i]); }
bool Player::isAnchor(int i, const BaseRoom* room) const { return(anchor[i]->is(room)); }
unsigned short Player::getThirst() const { return(thirst); }
int Player::numDiscoveredRooms() const { return(roomExp.size()); }
int Player::getUniqueObjId() const { return(uniqueObjId); }

//*********************************************************************
//						player set
//*********************************************************************

void Player::setTickDamage(unsigned short t) { tickDmg = t; }
void Player::setWarnings(unsigned short w) { warnings = w; }
void Player::addWarnings(unsigned short w) { setWarnings(w + warnings); }
void Player::subWarnings(unsigned short w) { setWarnings(w > warnings ? 0 : warnings - w); }
void Player::setWimpy(unsigned short w) { wimpy = w; }
void Player::setActualLevel(unsigned short l) { actual_level = MAX(1, MIN(l, MAXALVL)); }
void Player::setSecondClass(unsigned short c) { cClass2 = MAX(0, MIN(CLASS_COUNT - 1, c)); }
void Player::setGuild(unsigned short g) { guild = g; }
void Player::setGuildRank(unsigned short g) { guildRank = g; }
void Player::setNegativeLevels(unsigned short l) { negativeLevels = MAX(0, MIN(exp_to_lev(experience), l)); }
void Player::setLuck(int l) { luck = l; }
void Player::setWeaponTrains(unsigned short t) { weaponTrains = t; }
void Player::subWeaponTrains(unsigned short t) { setWeaponTrains(t > weaponTrains ? 0 : weaponTrains - t); }
void Player::setLostExperience(unsigned long e) { lostExperience = e; }
void Player::setLastPassword(bstring p) { lastPassword = p; }
void Player::setAfflictedBy(bstring a) { afflictedBy = a; }
void Player::setLastLogin(long l) { lastLogin = MAX(0, l); }
void Player::setLastInterest(long l) { lastInterest = MAX(0, l); }
void Player::setLastCommunicate(bstring c) { lastCommunicate = c; }
void Player::setLastCommand(bstring c) { lastCommand = c; lastCommand.trim(); }
void Player::setCreated() { created = time(0); }
void Player::setSurname(bstring s) { surname = s.left(20); }
void Player::setForum(bstring f) { forum = f; }
void Player::setAlias(Monster* m) { alias_crt = m; }
void Player::setBirthday() {
	const Calendar* calendar = gConfig->getCalendar();
	if(birthday)
		delete birthday;
	birthday = new cDay;
	birthday->setYear(calendar->getCurYear() - gConfig->getRace(getRace())->getStartAge());
	birthday->setDay(calendar->getCurDay());
	birthday->setMonth(calendar->getCurMonth());
}
void Player::delAnchor(int i) {
	if(anchor[i]) {
		delete anchor[i];
		anchor[i] = 0;
	}
}
void Player::setAnchor(int i, bstring a) {
	delAnchor(i);
	anchor[i] = new Anchor(a, this);
}
void Player::setThirst(unsigned short t) { thirst = t; }
void Player::setCustomColor(CustomColor i, char c) { customColors[i] = c; }


Monster::Monster() {
	reset();
}

Player::Player() {
	reset();
	mySock = NULL;
	// initial flags for new characters
	setFlag(P_NO_AUTO_WEAR);
}

Player* Creature::getMaster() {
	return((isPet() ? following : this)->getPlayer());
}

const Player* Creature::getConstMaster() const {
	return((isPet() ? following : this)->getConstPlayer());
}

bool Creature::isPlayer() const {
	return(type == PLAYER);
}
bool Creature::isMonster() const {
	return(type != PLAYER);
}

// Resets all common structure elements of creature
void Creature::crtReset() {
	moReset();

	myTarget = NULL;

	Creature* targeter;
	foreach(targeter, targetingThis) {
		targeter->clearTarget(false);
	}

	// Clear out any skills/factions/etc
	crtDestroy();

	zero(name, sizeof(name));
	zero(key, sizeof(key));

	poisonedBy = description = "";
	version = "0.00";

	fd = -1;
	level = cClass = race = alignment = experience =
		temp_experience = clan = 0;
	size = NO_SIZE;
	type = PLAYER;
	deathtype = DT_NONE;

	int i;
	coins.zero();
	zero(realm, sizeof(realm));
	zero(flags, sizeof(flags));
	zero(spells, sizeof(spells));
	zero(quests, sizeof(quests));
	zero(languages, sizeof(languages));
	questnum = 0;

	for(i=0; i<MAXWEAR; i++)
		ready[i] = 0;

	following = 0;
	first_fol = 0;
	first_obj = 0;
	first_enm = 0;
	first_tlk = 0;

	parent_rom = 0;
	area_room = 0;

	current_language = 0;
	afterProf = 0;
	memset(movetype, 0, sizeof(movetype));
	poison_dur = poison_dmg = 0;

	for(i=0; i<6; i++)
		proficiency[i] = 0;
	deity = 0;

	memset(spellTimer, 0, sizeof(spellTimer));
	armor = 0;

	for(i=0; i<21; i++)
		misc[i] = 0;
}

void Monster::reset() {
	// Call Creature::reset first
	crtReset();
	int i;

	info.clear();
	memset(attack, 0, sizeof(attack));
	memset(aggroString, 0, sizeof(aggroString));
	talk = "";

	baseRealm = NO_REALM;
	defenseSkill = weaponSkill = attackPower = 0;

	numwander = loadAggro = 0;
	memset(last_mod, 0, sizeof(last_mod));

	mobTrade = 0;
	skillLevel = 0;
	maxLevel = 0;
	memset(ttalk, 0, sizeof(ttalk));

	for(i=0; i<NUM_RESCUE; i++)
		rescue[i].clear();

	updateAggro = 0;
	cast = 0;
	magicResistance = 0;
	jail.clear();

	primeFaction = "";
	memset(cClassAggro, 0, sizeof(cClassAggro));
	memset(raceAggro, 0, sizeof(raceAggro));
	memset(deityAggro, 0, sizeof(deityAggro));

	std::list<TalkResponse*>::iterator tIt;
	for(tIt = responses.begin() ; tIt != responses.end() ; tIt++) {
		delete (*tIt);
	}
	responses.clear();
}

void Player::reset() {
	// Call Creature::reset first
	crtReset();
	cClass2 = wimpy = 0;
	barkskin = 0;
	weaponTrains = 0;
	bank.zero();
	created = 0;

	oldCreated = surname = lastCommand = lastCommunicate = password = title = tempTitle = "";
	lastPassword = afflictedBy = forum = "";
	tickDmg = lostExperience = pkwon = pkin = lastLogin = lastInterest = fishing = uniqueObjId = 0;

	memset(songs, 0, sizeof(songs));
	guild = guildRank = cClass2 = 0;

	int i;
	actual_level = warnings = 0;
	for(i=0; i<MAX_DIMEN_ANCHORS; i++)
		anchor[i] = 0;

	negativeLevels = 0;
	birthday = NULL;
	first_charm = 0;

	luck = 0;
	ansi = 0;
	alias_crt = 0;
	scared_of = 0;
	for(i=0; i<5; i++)
		tnum[i] = 0;
	timeout = 0;
	thirst = 0;

	resetCustomColors();
	lastPawn = 0;

	roomExp.clear();
	lore.clear();
	recipes.clear();
	std::map<int, QuestCompletion*>::iterator qIt;
	for(qIt = questsInProgress.begin() ; qIt != questsInProgress.end() ; qIt++) {
		delete (*qIt).second;
	}
	questsInProgress.clear();
	questsCompleted.clear();
}

Creature::Creature() {
	hooks.setParent(this);
}

void Creature::CopyCommon(const Creature& cr) {
	int		i=0;

	moCopy(cr);

	description = cr.description;
	for(i=0; i<3; i++) {
		strcpy(key[i], cr.key[i]);
	}
	fd = cr.fd;
	level = cr.level;
	type = cr.type;
	cClass = cr.cClass;
	race = cr.race;
	alignment = cr.alignment;
	experience = cr.experience;
	temp_experience = cr.temp_experience;
	poisonedBy = cr.poisonedBy;

	damage = cr.damage;

	clan = cr.clan;
	questnum = cr.questnum;
	size = cr.size;

	for(Realm r = MIN_REALM; r<MAX_REALM; r = (Realm)((int)r + 1))
		setRealm(cr.getRealm(r), r);

	for(i=0; i<CRT_FLAG_ARRAY_SIZE; i++)
		flags[i] = cr.flags[i];

	poison_dur = cr.poison_dur;
	poison_dmg = cr.poison_dmg;

	strength = cr.strength;
	dexterity = cr.dexterity;
	constitution = cr.constitution;
	intelligence = cr.intelligence;
	piety = cr.piety;

	hp = cr.hp;
	mp = cr.mp;
	pp = cr.pp;
	rp = cr.rp;

	hpTic = cr.hpTic;
	mpTic = cr.mpTic;
	ppTic = cr.ppTic;
	rpTic = cr.rpTic;

	armor = cr.armor;
	current_language = cr.current_language;

	deity = cr.deity;

	for(i=0; i<MAXWEAR; i++)
		ready[i] = cr.ready[i];

	following = cr.following;
	first_fol = cr.first_fol;
	first_obj = cr.first_obj;
	first_enm = cr.first_enm;
	first_tlk = cr.first_tlk;

	room = cr.room;
	parent_rom = cr.parent_rom;
	area_room = cr.area_room;

	for(i=0; i<6; i++)
		saves[i] = cr.saves[i];
	for(i=0; i<16; i++)
		languages[i] = cr.languages[i];
	for(i=0; i<32; i++) {
		spells[i] = cr.spells[i];
		quests[i] = cr.quests[i];
	}

	coins.set(cr.coins);

	for(i=0; i<6; i++)
		proficiency[i] = cr.proficiency[i];
	for(i=0; i<20; i++)
		daily[i] = cr.daily[i];
	for(i=0; i<128; i++)
		lasttime[i] = cr.lasttime[i];
	for(i=0; i<16; i++)
		spellTimer[i] = cr.spellTimer[i];

	factions = cr.factions;

	//skills = cr.skills;
	CrtSkill* skill;
	CrtSkill* crSkill;
	std::map<bstring, CrtSkill*>::const_iterator csIt;
	for(csIt = cr.skills.begin() ; csIt != cr.skills.end() ; csIt++) {
		crSkill = (*csIt).second;
		skill = new CrtSkill;
		(*skill) = (*crSkill);
		skills[crSkill->getName()] = skill;
	}

	effects.copy(&cr.effects, this);

	std::list<bstring>::const_iterator mIt;
	for(mIt = cr.minions.begin() ; mIt != cr.minions.end() ; mIt++) {
		minions.push_back(*mIt);
	}

	SpecialAttack* attack;
	std::list<SpecialAttack*>::const_iterator sIt;
	for(sIt = cr.specials.begin() ; sIt != cr.specials.end() ; sIt++) {
		attack = new SpecialAttack();
		(*attack) = *(*sIt);
		specials.push_back(attack);
	}

	attackPower = cr.attackPower;
}
void Player::doCopy(const Player& cr) {
	// We want a copy of what we're getting, so clear out anything that was here before
	reset();
	// Copy anything in common with the base class
	CopyCommon(cr);

	// Now copy player specfic stuff
	int i=0;
	created = cr.created;
	oldCreated = cr.oldCreated;

	title = cr.title;
	password = cr.getPassword();
	surname = cr.surname;
	forum = cr.forum;

	bank.set(cr.bank);

	lastPassword = cr.lastPassword;
	lastCommand = cr.lastCommand;
	lastCommunicate = cr.lastCommunicate;
	afflictedBy = cr.afflictedBy;
	lastLogin = cr.lastLogin;
	lastInterest = cr.lastInterest;
	tempTitle = cr.tempTitle;

	std::list<CatRef>::const_iterator it;
	if(!cr.roomExp.empty()) {
		for(it = cr.roomExp.begin() ; it != cr.roomExp.end() ; it++) {
			roomExp.push_back(*it);
		}
	}
	if(!cr.lore.empty()) {
		for(it = cr.lore.begin() ; it != cr.lore.end() ; it++) {
			lore.push_back(*it);
		}
	}

	std::list<int>::const_iterator rt;
	if(!cr.recipes.empty()) {
		for(rt = cr.recipes.begin() ; rt != cr.recipes.end() ; rt++) {
			recipes.push_back(*rt);
		}
	}

	cClass2 = cr.cClass2;
	wimpy = cr.wimpy;
	tickDmg = cr.tickDmg;
	lostExperience = cr.lostExperience;
	pkwon = cr.pkwon;
	pkin = cr.pkin;
	bound = cr.bound;
	previousRoom = cr.previousRoom;
	statistics = cr.statistics;

	for(i=0; i<32; i++)
		songs[i] = cr.songs[i];

	guild = cr.guild;
	guildRank = cr.guildRank;
	cClass2 = cr.cClass2;
	focus = cr.focus;

	negativeLevels = cr.negativeLevels;
	actual_level = cr.actual_level;
	warnings = cr.warnings;

	for(i=0; i<3; i++)
		strcpy(movetype[i], cr.movetype[i]);

	for(i=0; i<MAX_DIMEN_ANCHORS; i++) {
		if(cr.anchor[i]) {
			anchor[i] = new Anchor;
			*anchor[i] = *cr.anchor[i];
		}
	}

	for(i=0; i<MAX_BUILDER_RANGE; i++) {
		bRange[i] = cr.bRange[i];
	}

	for(i=0; i<21; i++)
		misc[i] = cr.misc[i];

	if(cr.birthday) {
		birthday = new cDay;
		*(birthday) = *(cr.birthday);
	}

	strcpy(customColors, cr.customColors);
	thirst = cr.thirst;
	weaponTrains = cr.weaponTrains;
	attackTimer = cr.attackTimer;

	// TODO: Look at this and make sure it's doing what i want it to do
	std::pair<int, QuestCompletion*> p;
	QuestCompletion *oldQuest;
	QuestCompletion *newQuest;
	foreach(p, cr.questsInProgress) {
		oldQuest = p.second;
		newQuest = new QuestCompletion(*(oldQuest));
		//*(newQuest) = *(oldQuest);
		questsInProgress[p.first] = newQuest;
	}
	foreach(const int & q, cr.questsCompleted) {
		questsCompleted.push_back(q);
	}
}

void Monster::doCopy(const Monster& cr) {
	// We want a copy of what we're getting, so clear out anything that was here before
	reset();
	// Copy anything in common with the base class
	CopyCommon(cr);

	// Now do monster specific copies
	int i;
	strcpy(aggroString, cr.aggroString);
	talk = cr.talk;

	strcpy(last_mod, cr.last_mod);
	strcpy(ttalk, cr.ttalk);

	for(i=0; i<3; i++)
		strcpy(attack[i], cr.attack[i]);
	for(i=0; i<NUM_RESCUE; i++)
		rescue[i] = cr.rescue[i];

	baseRealm = cr.baseRealm;

	mobTrade = cr.mobTrade;
	skillLevel = cr.skillLevel;
	maxLevel = cr.maxLevel;
	jail = cr.jail;
	cast = cr.cast;

	loadAggro = cr.loadAggro;
	info = cr.info;

	updateAggro = cr.updateAggro;
	numwander = cr.numwander;

	for(i=0; i<10; i++)
		carry[i] = cr.carry[i];

	primeFaction = cr.primeFaction;
	magicResistance = cr.magicResistance;


	for(i=0; i<NUM_ASSIST_MOB; i++)
		assist_mob[i] = cr.assist_mob[i];
	for(i=0; i<NUM_ENEMY_MOB; i++)
		enemy_mob[i] = cr.enemy_mob[i];

	for(i=0; i<3; i++) {
		strcpy(movetype[i], cr.movetype[i]);
	}

	for(i=0; i<4; i++) {
		cClassAggro[i] = cr.cClassAggro[i];
		raceAggro[i] = cr.raceAggro[i];
		deityAggro[i] = cr.deityAggro[i];
	}

	for(i=0; i<21; i++)
		misc[i] = cr.misc[i];


	defenseSkill = cr.defenseSkill;
	weaponSkill = cr.weaponSkill;

	foreach(TalkResponse* response, cr.responses) {
		responses.push_back(new TalkResponse(*response));
	}
}
Monster::Monster(Monster& cr) {
	doCopy(cr);
}
Monster::Monster(const Monster& cr) {
	doCopy(cr);
}

Monster& Monster::operator=(const Monster& cr) {
	doCopy(cr);
	return(*this);
}


Player::Player(Player& cr) {
	doCopy(cr);
}
Player::Player(const Player& cr) {
	doCopy(cr);
}

Player& Player::operator=(const Player& cr) {
	doCopy(cr);
	return(*this);
}

// Things all subclasses must destroy
void Creature::crtDestroy() {
	moDestroy();

	clearTarget();

	Creature* targeter;
	foreach(targeter, targetingThis) {
		targeter->clearTarget(false);
	}

	factions.clear();

	CrtSkill* skill;
	std::map<bstring, CrtSkill*>::iterator csIt;
	for(csIt = skills.begin() ; csIt != skills.end() ; csIt++) {
		skill = (*csIt).second;
		delete skill;
	}
	skills.clear();

	effects.removeAll();
	minions.clear();

	SpecialAttack* attack;
	std::list<SpecialAttack*>::iterator sIt;
	for(sIt = specials.begin() ; sIt != specials.end() ; sIt++) {
		attack = (*sIt);
		delete attack;
		(*sIt) = NULL;
	}
	specials.clear();
}

Monster::~Monster() {
	crtDestroy();
}

Player::~Player() {
	crtDestroy();
	int i = 0;

	if(birthday) {
		delete birthday;
		birthday = NULL;
	}

	for(i=0; i<MAX_DIMEN_ANCHORS; i++)
		if(anchor[i])
			delete anchor[i];

	std::pair<int, QuestCompletion*> p;
	QuestCompletion *quest;
	foreach(p, questsInProgress) {
		quest = p.second;
		delete quest;
	}

	questsInProgress.clear();
	questsCompleted.clear();
	setLastPawn(0);
}

bool Creature::isPet() const {
	if(isPlayer())
		return(false);
	return(flagIsSet(M_PET) && following);
}

bool Creature::isPublicWatcher() const {
	if(isMonster())
		return(false);
	return(flagIsSet(P_WATCHER) && !flagIsSet(P_SECRET_WATCHER));
}

bool Creature::isWatcher() const {
	if(isMonster())
		return(false);
	return(isCt() || flagIsSet(P_WATCHER));
}

bool Creature::isStaff() const {
	if(isMonster())
		return(false);
	return(cClass >= BUILDER);
}

bool Creature::isCt() const {
	if(isMonster())
		return(false);
	return(cClass >= CARETAKER);
}

bool Creature::isDm() const {
	if(isMonster())
		return(false);
	return(cClass == DUNGEONMASTER);
}

bool Creature::isAdm() const {
	if(isMonster())
		return(false);
	return((!strcmp(name, "Bane") || !strcmp(name, "Dominus") || !strcmp(name, "Ocelot")));
}

bool Creature::flagIsSet(int flag) const {
	return(flags[flag/8] & 1<<(flag%8));
}
void Creature::setFlag(int flag) {
	flags[flag/8] |= 1<<(flag%8);
	if(flag == P_NO_TRACK_STATS && isPlayer())
		getPlayer()->statistics.track = false;
}
void Creature::clearFlag(int flag) {
	flags[flag/8] &= ~(1<<(flag%8));
	if(flag == P_NO_TRACK_STATS && isPlayer())
		getPlayer()->statistics.track = true;
}
bool Creature::toggleFlag(int flag) {
	if(flagIsSet(flag))
		clearFlag(flag);
	else
		setFlag(flag);
	return(flagIsSet(flag));
}


bool Creature::languageIsKnown(int lang) const {
	return(languages[lang/8] & 1<<(lang%8));
}
void Creature::learnLanguage(int lang) {
	languages[lang/8] |= 1<<(lang%8);
}
void Creature::forgetLanguage(int lang) {
	languages[lang/8] &= ~(1<<(lang%8));
}


bool Creature::spellIsKnown(int spell) const {
	return(spells[spell/8] & 1<<(spell%8));
}
void Creature::learnSpell(int spell) {
	spells[spell/8] |= 1<<(spell%8);
}
void Creature::forgetSpell(int spell) {
	spells[spell/8] &= ~(1<<(spell%8));
}


bool Player::questIsSet(int quest) const {
	return(quests[quest/8] & 1<<(quest%8));
}
void Player::setQuest(int quest) {
	quests[quest/8] |= 1<<(quest%8);
}
void Player::clearQuest(int quest) {
	quests[quest/8] &= ~(1<<(quest%8));
}


bool Player::songIsKnown(int song) const {
	return(songs[song/8] & 1<<(song%8));
}
void Player::learnSong(int song) {
	songs[song/8] |= 1<<(song%8);
}
void Player::forgetSong(int song) {
	songs[song/8] &= ~(1<<(song%8));
}

//*********************************************************************
//						isRace
//*********************************************************************
// lets us determine race equality with the presence of subraces

bool isRace(int subRace, int mainRace) {
	return(mainRace == subRace || gConfig->getRace(subRace)->getParentRace() == mainRace);
}
bool Creature::isRace(int r) const {
	return(::isRace(race, r));
}



const char *Creature::hisHer() const {
	Sex sex = getSex();
	if(sex == SEX_FEMALE)
		return("her");
	else if(sex == SEX_MALE)
		return("his");
	return("its");
}

const char *Creature::himHer() const {
	Sex sex = getSex();
	if(sex == SEX_FEMALE)
		return("her");
	else if(sex == SEX_MALE)
		return("him");
	return("it");
}

const char *Creature::heShe() const {
	Sex sex = getSex();
	if(sex == SEX_FEMALE)
		return("she");
	else if(sex == SEX_MALE)
		return("he");
	return("it");
}

const char *Creature::upHisHer() const {
	Sex sex = getSex();
	if(sex == SEX_FEMALE)
		return("Her");
	else if(sex == SEX_MALE)
		return("His");
	return("Its");
}

const char *Creature::upHeShe() const {
	Sex sex = getSex();
	if(sex == SEX_FEMALE)
		return("She");
	else if(sex == SEX_MALE)
		return("He");
	return("It");
}

//********************************************************************
//						getClassString
//********************************************************************

bstring Player::getClassString() const {
	std::ostringstream cStr;
	cStr << get_class_string(cClass);
	if(cClass2)
		cStr << "/" << get_class_string(cClass2);
	return(cStr.str());
}

//********************************************************************
//						canSee
//********************************************************************

bool Creature::canSee(const BaseRoom* room, bool p) const {
	if(isStaff())
		return(true);
	const Player* player = getConstPlayer();

	// blind people can't see anything
	if(isBlind()) {
		if(p) {
			printColor("^CYou're blind!^x\n");
			printColor("^yIt's too dark to see.^x\n");
		}
		return(false);
	}

	// magic vision overcomes all darkness
	if(isEffected("infravision"))
		return(true);

	// magic dark can only be overcome by magic vision
	if(room->isMagicDark()) {
		if(p) {
			printColor("^CIt's unnaturally dark here.\n");
			printColor("^yIt's too dark to see.\n");
		}
		return(false);
	}

	// room is affected by normal darkness
	if(room->isNormalDark()) {
		// there are several sources of normal vision
		bool	normal_sight = gConfig->getRace(race)->hasInfravision() ||
	    	isUndead() || isEffected("lycanthropy") || (player && player->getLight());
		ctag*	cp=0;

		// if they cant see, maybe someone else in the room has light for them
		if(!normal_sight) {
			cp = room->first_ply;
			while(cp) {
				if(cp->crt->getPlayer()->getLight()) {
					normal_sight = true;
					break;
				}
				cp = cp->next_tag;
			}
		}

		if(!normal_sight) {
			if(p)
				printColor("^yIt's too dark to see.\n");
			return(false);
		}
	}

	// not any form of dark, then they can see
	return(true);
}

//********************************************************************
//						canSee
//********************************************************************
// This only handles total invisibility - the creature cannot see the target
// at all. This does not handle concealment, such as being hidden.
// This function can be called on an empty creature to check to see if
// an object can be seen by anyone.

bool Creature::canSee(const Object* object) const {

	if(!object)
		return(false);

	if(this && isStaff())
		return(true);
	if(object->flagIsSet(O_INVISIBLE) && (this && !isEffected("detect-invisible")))
		return(false);

	return(true);
}


//********************************************************************
//						canSee
//********************************************************************
// This only handles total invisibility - the creature cannot see the target
// at all. This does not handle concealment, such as being hidden.

bool Creature::canSee(const Exit *exit) const {

	if(!exit)
		return(false);

	if(isStaff())
		return(true);

	// handle NoSee right away
	if(exit->flagIsSet(X_NO_SEE))
		return(false);
	if(exit->flagIsSet(X_INVISIBLE) && !isEffected("detect-invisible"))
		return(false);

	return(true);
}


//********************************************************************
//						canSee
//********************************************************************
// This only handles total invisibility - the creature cannot see the target
// at all. This does not handle concealment, such as being hidden.
// The skip boolean skips the invis/mist checks. In effect, it only runs
// staff invisibility. This is used in group and groupline.

bool Creature::canSee(const Creature* target, bool skip) const {

	if(!target)
		return(false);

	// we are a player
	if(isPlayer()) {

		if(target->isPlayer()) {
			if(target->isDm() && target->flagIsSet(P_DM_INVIS) && !isDm())
				return(false);
			if(target->isCt() && target->flagIsSet(P_DM_INVIS) && !isCt())
				return(false);
			if(target->isStaff() && target->flagIsSet(P_DM_INVIS) && !isStaff())
				return(false);
			if(target->flagIsSet(P_INCOGNITO) && !isCt() && getRoom() != target->getRoom())
				return(false);

			if(!skip) {
				if(target->isInvisible() && !isEffected("detect-invisible") && !isStaff())
					return(false);
				if(target->flagIsSet(P_MISTED) && !isEffected("true-sight") && !isStaff())
					return(false);
			}

		} else {

			if(!skip) {
				if(target->isInvisible() && !isEffected("detect-invisible") && !isStaff())
					return(false);
			}

		}

	// we are a monster
	} else {

		if(target->isPlayer()) {
			if(target->isStaff() && target->flagIsSet(P_DM_INVIS))
				return(false);

			if(!skip) {
				if(target->isInvisible() && !isEffected("detect-invisible"))
					return(false);
				if(target->flagIsSet(P_MISTED) && !isEffected("true-sight"))
					return(false);
			}
		} else {

			if(!skip) {
				if(target->isInvisible() && !isEffected("detect-invisible"))
					return(false);
			}

		}

	}

	return(true);
}


//********************************************************************
//						canEnter
//********************************************************************
// Determines if a player/monster can enter the exit provided. If p is not 0,
// it will also display a reason why. This only handles absolutely-unable-to-
// enter. M_BLOCK_EXIT is not handled because players can still enter those
// exits under certain circumstances (ie, flee).
//
// Pets are handled differently. They obey special rules for rooms because
// returning false here would prevent the player from entering the room.

bool Creature::canEnter(const Exit *exit, bool p) const {
	const Calendar* calendar=0;
	int staff = isStaff();

	if(!exit)
		return(false);

	if(isMonster())
		p = false;

	if(exit->target.mapmarker.getArea()) {
		Area *area = gConfig->getArea(exit->target.mapmarker.getArea());
		if(!area)
			return(false);
		// y coords are stored upside down in the array
		// impassable terrain
		if(!area->canPass(this, &exit->target.mapmarker, true)) {
			if(p) checkStaff("You can't go there!\n");
			if(!staff) return(false);
		}
	}


	// pets can go anywhere
	if(isPet())
		return(true);


	if(exit->isWall("wall-of-force")) {
		if(p) checkStaff("^sA wall of force blocks passage in that direction.\n");
		if(!staff) return(false);
	}
	if(exit->flagIsSet(X_CLOSED)) {
		if(p) checkStaff("You have to open it first.\n");
		if(!staff) return(false);
	}
	if(exit->flagIsSet(X_LOCKED)) {
		if(p) checkStaff("It's locked.\n");
		if(!staff) return(false);
	}

	if(exit->flagIsSet(X_DM_ONLY) || exit->flagIsSet(X_NO_SEE)) {
		if(p) checkStaff("You cannot go that way.\n");
		if(!staff) return(false);
	}


	if(exit->getSize() && size > exit->getSize()) {
		if(p) checkStaff("Only %s and smaller creatures may go there.\n", getSizeName(exit->getSize()).c_str());
		if(!staff) return(false);
	}


	if( (exit->flagIsSet(X_MALE_ONLY) && getSex() != SEX_MALE) ||
		(exit->flagIsSet(X_FEMALE_ONLY) && getSex() != SEX_FEMALE)
	) {
		if(p) checkStaff("Your sex prevents you from going that way.\n");
		if(!staff) return(false);
	}

	if( (exit->flagIsSet(X_NIGHT_ONLY) && isDay()) ||
		(exit->flagIsSet(X_DAY_ONLY) && !isDay())
	) {
		if(p) checkStaff("You may not go that way %s.\n", isDay() ? "during the day" : "at night");
		if(!staff) return(false);
	}

	if(	getRoom()->getTollkeeper() &&
		(exit->flagIsSet(X_TOLL_TO_PASS) || exit->flagIsSet(X_LEVEL_BASED_TOLL))
	) {
		if(p) checkStaff("You must pay a toll of %lu gold coins to go through the %s.\n", tollcost(this->getConstPlayer(), exit, 0), exit->name);
		if(!staff) return(false);
	}


	if(exit->clanRestrict(this)) {
		if(p) checkStaff("Your allegiance prevents you from going that way.\n");
		if(!staff) return(false);
	}
	if(exit->classRestrict(this)) {
		if(p) checkStaff("Your class prevents you from going that way.\n");
		if(!staff) return(false);
	}
	if(exit->raceRestrict(this)) {
		if(p) checkStaff("Your race prevents you from going that way.\n");
		if(!staff) return(false);
	}
	if(exit->alignRestrict(this)) {
		if(p) checkStaff("Your alignment prevents you from going that way.\n");
		if(!staff) return(false);
	}

	calendar = gConfig->getCalendar();
	if(exit->flagIsSet(X_WINTER) && calendar->whatSeason() == WINTER) {
		if(p) checkStaff("Heavy winter snows prevent you from going that way.\n");
		if(!staff) return(false);
	}
	if(exit->flagIsSet(X_SPRING) && calendar->whatSeason() == SPRING) {
		if(p) checkStaff("Spring floods prevent you from going that way.\n");
		if(!staff) return(false);
	}
	if(exit->flagIsSet(X_SUMMER) && calendar->whatSeason() == SUMMER) {
		if(p) checkStaff("The summer heat prevent you from going that way.\n");
		if(!staff) return(false);
	}
	if(exit->flagIsSet(X_AUTUMN) && calendar->whatSeason() == AUTUMN) {
		if(p) checkStaff("You cannot go that way in autumn.\n");
		if(!staff) return(false);
	}



	// we are a player
	if(isPlayer()) {

		if(exit->flagIsSet(X_NAKED) && getWeight()) {
			if(p) checkStaff("You cannot bring anything through that exit.\n");
			if(!staff) return(false);
		}

		if(!canSee(exit)) {
			if(p) checkStaff("You don't see that exit.\n");
			if(!staff) return(false);
		}

		if(exit->flagIsSet(X_NEEDS_FLY) && !isEffected("fly")) {
			if(p) checkStaff("You must fly to go that way.\n");
			if(!staff) return(false);
		}

		if(exit->flagIsSet(X_NO_MIST) && flagIsSet(P_MISTED)) {
			if(p) checkStaff("You may not go that way in mist form.\n");
			if(!staff) return(false);
		}


		Monster* guard = getRoom()->getGuardingExit(exit);
		if(guard) {
			if(p) checkStaff("%M blocks your exit.\n", guard);
			if(!staff) return(false);
		}

	// we are a monster
	} else {

		if(exit->flagIsSet(X_NO_WANDER))
			return(false);
		if(exit->flagIsSet(X_TO_STORAGE_ROOM))
			return(false);
		if(exit->flagIsSet(X_TO_BOUND_ROOM))
			return(false);

	}

	return(true);
}



//********************************************************************
//						canEnter
//********************************************************************

bool Creature::canEnter(const Room* room, bool p) const {

	// staff may always go anywhere
	bool staff = isStaff();

	if(!room) {
		if(p) print("Off the map in that direction.\n");
		if(staff) printColor("^eThat room does not exist.\n");
		return(false);
	}

	// special rules for pets
	if(isPet()) {
		const Monster* mThis = getConstMonster();
		if( room->isUnderwater() &&
			mThis->getBaseRealm() != WATER &&
			!isEffected("breathe-water") &&
			!doesntBreathe()
		)
			return(false);
		return(true);
	}


	if(isMonster())
		p = false;

	if(size && room->getSize() && size > room->getSize()) {
		if(p) checkStaff("Only %s and smaller creatures may go there.\n", getSizeName(room->getSize()).c_str());
		if(!staff) return(false);
	}

	// we are a player
	if(isPlayer()) {

		if(room->flagIsSet(R_SHOP_STORAGE)) {
			if(p) checkStaff("You cannot enter a shop's storage room.\n");
			if(!staff) return(false);
		}
		if(room->getLowLevel() > level) {
			if(p) checkStaff("You must be at least level %d to go there.\n", room->getLowLevel());
			if(!staff) return(false);
		}
		if(level > room->getHighLevel() && room->getHighLevel()) {
			if(p) checkStaff("Only players under level %d may go there.\n", room->getHighLevel()+1);
			if(!staff) return(false);
		}
		if(room->deityRestrict(this)) {
			if(p) checkStaff("Only members of the proper faith may go there.\n");
			if(!staff) return(false);
		}
		if(room->isFull()) {
			if(p) checkStaff("That room is full.\n");
			if(!staff) return(false);
		}
		if(room->flagIsSet(R_NO_MIST) && flagIsSet(P_MISTED)) {
			if(p) checkStaff("You may not enter there in mist form.\n");
			if(!staff) return(false);
		}
		if(!staff && room->flagIsSet(R_CONSTRUCTION)) {
			print("Off the map in that direction.\n");
			return(false);
		}

		if(!Property::canEnter(getConstPlayer(), room, p))
			return(false);

	// we are a monster
	} else {

		// no rules for monsters

	}

	return(true);
}


//********************************************************************
//						getWeight
//********************************************************************
// This function calculates the total weight that a player (or monster)
// is carrying in their inventory.

int Creature::getWeight() const {
	int		i=0, n=0;
	otag	*op=0;

	op = first_obj;
	while(op) {
		if(!op->obj->flagIsSet(O_WEIGHTLESS_CONTAINER))
			n += op->obj->getActualWeight();
		op = op->next_tag;
	}

	for(i=0; i<MAXWEAR; i++)
		if(ready[i])
			n += ready[i]->getActualWeight();

	return(n);
}


//********************************************************************
//						maxWeight
//********************************************************************
// This function returns the maximum weight a player can be allowed to
// hold in their inventory.

int Creature::maxWeight() const {
	int	n = 20 + strength.getCur();
	if(cClass == BERSERKER || isCt())
		n += level*10;
	return(n);
}

//********************************************************************
//						tooBulky
//********************************************************************

bool Creature::tooBulky(int n) const {
	int		total=0, i=0, max=0;
	otag	*op=0;

	if(isCt())
		return(0);

	op = first_obj;
	while(op) {
		total += op->obj->getActualBulk();
		op = op->next_tag;
	}

	for(i=0; i<MAXWEAR; i++)
		if(ready[i])
			total += (ready[i]->getActualBulk()/2);

	max = getMaxBulk();

	if(flagIsSet(P_DEEPPOCKETS))
		max *= 2;

	return(n + getTotalBulk() > max);
}

//********************************************************************
//						getTotalBulk
//********************************************************************

int	Creature::getTotalBulk() const {
	otag	*op=0;
	int		n=0, i=0;

	op = first_obj;
	while(op) {
		n += op->obj->getActualBulk();
		op = op->next_tag;
	}

	for(i=0; i<MAXWEAR; i++)
		if(ready[i])
			n += (ready[i]->getActualBulk()/2);

	return(n);
}

//********************************************************************
//						getMaxBulk
//********************************************************************

int Creature::getMaxBulk() const {
	switch(size) {
	case SIZE_FINE:
		return(10);
	case SIZE_DIMINUTIVE:
		return(30);
	case SIZE_TINY:
		return(60);
	case SIZE_SMALL:
		return(105);
	case SIZE_LARGE:
		return(185);
	case SIZE_HUGE:
		return(215);
	case SIZE_GARGANTUAN:
		return(245);
	case SIZE_COLOSSAL:
		return(275);
	case SIZE_MEDIUM:
	default:
		return(140);
	}
}

//********************************************************************
//						willFit
//********************************************************************

bool Creature::willFit(const Object* object) const {
	if(isStaff())
		return(true);

	if(size && object->getSize()) {
		if(size == object->getSize())
			return(true);

		// rings must be exact size
		if(object->getWearflag() == FINGER)
			return(false);

		// weapons and shields can be +- 1 category
		if(	(	object->getType() == WEAPON ||
				(object->getType() == ARMOR && object->getWearflag() == SHIELD) ) &&
			abs(size - object->getSize()) == 1 )
			return(true);

		// other armor can only be larger
		if(object->getType() == ARMOR && size - object->getSize() == -1)
			return(true);

		// if its wrong size, it cant be used
		return(false);
	}

	return(true);
}

//********************************************************************
//						canWear
//********************************************************************

bool Player::canWear(const Object* object, bool all) const {
	ASSERTLOG(object);

	if(!object->getWearflag() || object->getWearflag() == WIELD || object->getWearflag() == HELD) {
		if(!all)
			print("You can't wear that.\n");
		return(false);
	}

	bstring armorType = object->getArmorType();
	if((object->getType() == ARMOR && !object->isLightArmor() &&
			(object->getWearflag() == BODY || object->getWearflag() == ARMS || object->getWearflag() == HANDS)) &&
	        (ready[HELD-1] && ready[HELD-1]->getType() < 6) ) {
		printColor("You can't wear %P and also use a second weapon.\n", object);
		printColor("%O would hinder your movement too much.\n", object);
		return(false);
	}

	if(object->getWearflag() != FINGER && object->getWearflag() != SHIELD  &&
	        object->getType() == ARMOR && !knowsSkill(armorType)) {
		if(!all)
			printColor("You can't use %P; you lack the ability to wear %s armor.\n", object, armorType.c_str());
		return(false);
	}

	if(object->getWearflag() == FINGER && ready[FINGER1-1] &&
	        ready[FINGER2-1] && ready[FINGER3-1] &&
	        ready[FINGER4-1] && ready[FINGER5-1] &&
	        ready[FINGER6-1] && ready[FINGER7-1] &&
	        ready[FINGER8-1]) {
		if(!all)
			print("You don't have any more fingers left.\n");
		return(false);
	}

	if(object->getWearflag() != FINGER && ready[object->getWearflag()-1]) {
		if(!all) {
			printColor("You cannot wear %1P.\nYou're already wearing %1P.\n",
				object, ready[object->getWearflag()-1]);
		}
		return(false);
	}

	if(object->isHeavyArmor() && inCombat() && checkHeavyRestrict("")) {
		if(!all) {
			printColor("^RYou're too busy fighting to fumble around with heavy armor right now!^x\n");
		}
		return(false);
	}
	return(true);
}

//********************************************************************
//						canUse
//********************************************************************

bool Player::canUse(Object* object, bool all) {
	ASSERTLOG(object);

	if(!willFit(object)) {
		if(!all)
			printColor("%O isn't the right size for you.\n", object);
		return(false);
	}

	if(	size &&
		object->getSize() &&
		size != object->getSize() &&
		object->getWearflag() != HELD-1
	) {
		if(!all)
			printColor("Using %P is awkward due to its size.\n", object);
	}

	if(object->getType() == WEAPON) {
		if(object->getWeaponType() == "none") {
			if(!all)
				printColor("You lack the skills to wield %P.\n", object);
			return(false);
		}
		if(!knowsSkill(object->getWeaponType())) {
			if(!all)
				print("You are not skilled with %s.\n", gConfig->getSkillDisplayName(object->getWeaponType()).c_str());
			return(false);
		}
	}

	if(isEffected("lycanthropy") && flagIsSet(P_FRENZY)) {
		if(!all)
			print("You cannot do that while frenzied.\n");
		return(false);
	}

	if(object->getShotscur() < 1 && object->getType() != WAND) {
		if(!all)
			print("You can't. It's broken.\n");
		return(false);
	}

	if(object->doRestrict(this, !all))
		return(false);

	return(true);
}

//********************************************************************
//						canWield
//********************************************************************

bool Creature::canWield(const Object* object, int n) const {
	int		wielding=0, holding=0, shield=0, second=0;

	if(ready[WIELD-1])
		wielding = 1;
	if(ready[HELD-1])
		holding = 1;
	if(ready[HELD-1] && ready[HELD-1]->getType() < ARMOR)
		second = 1;
	if(ready[SHIELD-1])
		shield = 1;

	switch (n) {
	case HOLDOBJ:
		if(second) {
			print("You're wielding a weapon in your off hand. You can't hold that.\n");
			return(false);
		}
		if(holding) {
			print("You're already holding something.\n");
			return(false);
		}
		if(shield && !ready[SHIELD-1]->flagIsSet(O_SMALL_SHIELD)) {
			print("Your shield is being held by your off hand. You can't hold that.\n");
			return(false);
		}
		if(wielding && ready[WIELD-1]->needsTwoHands()) {
			printColor("You're using both hands to wield %P!\n", ready[WIELD-1]);
			return(false);

		}
		break;
	case WIELDOBJ:
		if(holding && object->needsTwoHands()) {
			printColor("You need both hands to wield %P.\nYou have %P in your off hand.\n", object, ready[HELD-1]);
			return(false);
		}
		if(shield && !ready[SHIELD-1]->flagIsSet(O_SMALL_SHIELD) && object->needsTwoHands()) {
			printColor("You need both hands to wield %P.\n%O uses your off hand.\n", object, ready[SHIELD-1]);
			return(false);
		}

		if(wielding) {
			printColor("You're already wielding %P.\n", ready[WIELD-1]);
			return(false);
		}

		if(cClass == CLERIC) {
			bstring objCategory = object->getWeaponCategory();
			bstring objType = object->getWeaponType();
			switch(deity) {
			case CERIS:
				if(objCategory != "crushing" && objCategory != "ranged" && objType != "polearm") {
					print("%s clerics may only use crushing, pole, and ranged weapons.\n", gConfig->getDeity(deity)->getName().c_str());
					return(false);
				}
				break;
			case KAMIRA:
				if(objCategory == "ranged") {
					print("%s clerics may not use ranged weapons.\n", gConfig->getDeity(deity)->getName().c_str());
					return(false);
				}
				break;
			}

		}

		break;
	case SECONDOBJ:
		if(second) {
			printColor("You're already wielding %P in your off hand.\n", ready[HELD-1]);
			return(false);
		}
		if(holding) {
			printColor("You're already holding %P in your off hand.\n", ready[HELD-1]);
			return(false);
		}
		if(shield && !ready[SHIELD-1]->flagIsSet(O_SMALL_SHIELD)) {
			printColor("Your shield is being held by your off hand. You can't second %P.\n", object);
			return(false);
		}
		if(object->needsTwoHands()) {
			printColor("%O requires two hands and cannot be used as a second weapon.\n", object);
			return(false);
		}
		if(wielding && ready[WIELD-1]->needsTwoHands()) {
			printColor("You're using both hands to wield %P!\n", ready[WIELD-1]);
			return(false);
		}
		if(cClass == RANGER) {
			if(ready[BODY-1] && !ready[BODY-1]->isLightArmor()) {
				printColor("You must remove %P to wield a second weapon.\nIt is too heavy.\n", ready[BODY-1]);
				return(false);
			}
			if(ready[ARMS-1] && !ready[ARMS-1]->isLightArmor()) {
				printColor("You must remove %P to wield a second weapon.\nIt is too heavy.\n", ready[ARMS-1]);
				return(false);
			}
			if(ready[HANDS-1] && !ready[HANDS-1]->isLightArmor()) {
				printColor("You must remove %P to wield a second weapon.\nIt is too heavy.\n", ready[HANDS-1]);
				return(false);
			}
		}
		break;
	case SHIELDOBJ:
		if(shield) {
			print("You're already wearing a shield.\n");
			return(false);
		}
		if(holding && !object->flagIsSet(O_SMALL_SHIELD)) {
			printColor("You are using your shield arm to hold %P.\n", ready[HELD-1]);
			return(false);
		}
		if(wielding && !object->flagIsSet(O_SMALL_SHIELD) && ready[WIELD-1]->needsTwoHands()) {
			printColor("You're using both arms to wield %P!\n", ready[WIELD-1]);
			return(false);
		}
		break;
	}// end switch

	return(true);
}

//********************************************************************
//						getInventoryValue
//********************************************************************

unsigned long Creature::getInventoryValue() const {
	int		a=0;
	long	total=0;
	otag	*op=0, *cop=0;
	Object	*object=0, *object2=0, *object3=0;

	if(isMonster())
		return(0);

	op = first_obj;
	while(op) {
		object = op->obj;

		if(object->getType() == CONTAINER) {
			cop = object->first_obj;
			while(cop) {
				object2 = cop->obj;
				if(object2->getType() == SCROLL || object2->getType() == POTION || object2->getType() == SONGSCROLL) {
					cop = cop->next_tag;
					continue;
				}

				if(object2->getShotscur() < 1 || object2->flagIsSet(O_NO_PAWN)) {
					cop = cop->next_tag;
					continue;
				}

				if(object2->value[GOLD] < 20) {
					cop = cop->next_tag;
					continue;
				}

				total += MIN(MAXPAWN,object2->value[GOLD]/2);
				total = MAX(0,MIN(2000000000,total));
				cop = cop->next_tag;
			}
		}

		if(object->getType() == SCROLL || object->getType() == POTION || object->getType() == SONGSCROLL) {
			op = op->next_tag;
			continue;
		}

		if((object->getShotscur() < 1 && object->getType() != CONTAINER)
		        || object->flagIsSet(O_NO_PAWN)) {
			op = op->next_tag;
			continue;
		}

		if(object->value[GOLD] < 20) {
			op = op->next_tag;
			continue;
		}

		total += MIN(MAXPAWN,object->value[GOLD]/2);
		total = MAX(0,MIN(2000000000,total));

		op = op->next_tag;
	}

	for(a=0;a<MAXWEAR;a++) {
		if(!ready[a])
			continue;
		object3 = ready[a];


		if(object3->getType() == CONTAINER) {
			cop = object3->first_obj;
			while(cop) {
				object2 = cop->obj;
				if(cop->obj->getType() == SCROLL || cop->obj->getType() == POTION || cop->obj->getType() == SONGSCROLL) {
					cop = cop->next_tag;
					continue;
				}
				if(cop->obj->getShotscur() < 1 || cop->obj->flagIsSet(O_NO_PAWN)) {
					cop = cop->next_tag;
					continue;
				}

				if(cop->obj->value[GOLD] < 20) {
					cop = cop->next_tag;
					continue;
				}

				total += MIN(MAXPAWN,cop->obj->value[GOLD]);
				total = MAX(0,MIN(2000000000,total));
				cop = cop->next_tag;
			}
		}

		if(object3->getType() == SCROLL || object3->getType()== POTION || object3->getType() == SONGSCROLL)
			continue;
		if((object3->getShotscur() < 1 && object3->getType() != CONTAINER)
		        || object3->flagIsSet(O_NO_DROP) || object3->flagIsSet(O_NO_PAWN))
			continue;
		if(object3->value[GOLD] < 20)
			continue;

		total+=MIN(MAXPAWN,object3->value[GOLD]/2);
		total = MAX(0,MIN(2000000000,total));
	}

	return(total);
}

//********************************************************************
//						isBrittle
//********************************************************************

bool Creature::isBrittle() const {
	return(isPlayer() && cClass == LICH);
}

//********************************************************************
//						isUndead
//********************************************************************

bool Creature::isUndead() const {
	if(cClass == LICH)
		return(true);
	if(isEffected("vampirism"))
		return(true);

	if(isMonster()) {
		if(monType::isUndead(type))
			return(true);
		if(flagIsSet(M_UNDEAD))
			return(true);
	}
	return(false);
}

//********************************************************************
//						save
//********************************************************************
// This function saves a player when the game decides to. It does
// not issue a message that the player was saved. This should be called
// instead of write_ply becuase it handles saving worn items properly
//
// This function saves a player's char. Since items need to be un-readied
// before a player can be saved to a file, this function makes a duplicate
// of the player, unreadies everything on the duplicate, and then saves
// the duplicate to the file. Afterwards, the duplicate is freed from
// memory.

int Player::save(bool updateTime, LoadType saveType) {
	Player* copy=0;
	Object	*obj[MAXWEAR];
	int		i=0, n=0;

	// having an update time option, which should be false for offline
	// operations, prevents aging of chars and keeps last login accurate
	if(updateTime) {
		lastLogin = time(0);
		lasttime[LT_AGE].interval += (lastLogin - lasttime[LT_AGE].ltime);
		lasttime[LT_AGE].ltime = lastLogin;
	}

	copy = new Player;
	if(!copy)
		merror("save", FATAL);

	*copy = *this;

	for(i=0; i<MAXWEAR; i++) {
		if(copy->ready[i]) {
			obj[n] = copy->unequip(i+1, UNEQUIP_ADD_TO_INVENTORY, false);
			obj[n]->setFlag(O_WORN);
			n++;
			copy->ready[i] = 0;
		}
	}

	if(!copy->name[0])
		return(1);
	copy->checkDarkness();

	if(copy->saveToFile(saveType) < 0)
		printf("*** ERROR: saveXml!\n");

	for(i=0; i<n; i++)
		copy->delObj(obj[i], false, false, true, false);

	delete copy;
	return(0);
}


//*********************************************************************
//						ableToDoCommand
//*********************************************************************

bool Creature::ableToDoCommand(cmd* cmnd) const {

	if(isMonster())
		return(true);

	if(flagIsSet(P_BRAINDEAD)) {
		print("You are brain-dead. You can't do that.\n");
		return(false);
	}

	// unconscious has some special rules
	if(flagIsSet(P_UNCONSCIOUS)) {
		// if they're sleeping, let them do only a few things
		if(cmnd && flagIsSet(P_SLEEPING) && (
			cmnd->myCommand->getName() == "wake" ||
			cmnd->myCommand->getName() == "snore" ||
			cmnd->myCommand->getName() == "murmur" ||
			cmnd->myCommand->getName() == "dream" ||
			cmnd->myCommand->getName() == "rollover"
		) )
			return(true);

		if(flagIsSet(P_SLEEPING))
			print("You can't do that while sleeping.\n");
		else
			print("How can you do that while unconscious?\n");
		return(false);
	}

	return(true);
}

//*********************************************************************
//						wake
//*********************************************************************

void Creature::wake(bstring str, bool noise) {
	if(isMonster())
		return;

	if(flagIsSet(P_SLEEPING)) {
		// can't wake sleeping people with noise
		if(noise && isEffected("deafness"))
			return;
		if(str != "") {
			printColor("%s\n", str.c_str());
			broadcast(getSock(), getRoom(), "%M wakes up.", this);
		}
		clearFlag(P_SLEEPING);
		clearFlag(P_UNCONSCIOUS);
		unhide();
	}
}


//*********************************************************************
//						isUnconscious
//*********************************************************************
// unconsciousness provides some special protection in combat for which
// sleeping people do not qualify. use this function when being unconscious
// will help

bool Creature::isUnconscious() const {
	if(isMonster())
		return(false);

	return(flagIsSet(P_UNCONSCIOUS) && !flagIsSet(P_SLEEPING));
}


//*********************************************************************
//						knockUnconscious
//*********************************************************************

void Creature::knockUnconscious(long duration) {
	if(isMonster())
		return;

	setFlag(P_UNCONSCIOUS);
	clearFlag(P_SLEEPING);
	lasttime[LT_UNCONSCIOUS].ltime = time(0);
	lasttime[LT_UNCONSCIOUS].interval = duration;
}


//*********************************************************************
//						isBraindead
//*********************************************************************

bool Creature::isBraindead()  const {
	if(isMonster())
		return(false);
	return(flagIsSet(P_BRAINDEAD));
}

//*********************************************************************
//						inCombat
//*********************************************************************
// we don't care if they are fighting people in other rooms -
// we only care if they're fighting someone in THIS room

bool Creature::inCombat(bool countPets) const {
	return(inCombat(0, countPets));
}

// target is used when you want to check for a player being in combat
// with a mob BESIDES the one pointed to by creature.
bool Creature::inCombat(const Creature* target, bool countPets) const {
	BaseRoom* room = getRoom();
	// people just logging in
	if(!room)
		return(false);
	const Monster* mThis = getConstMonster();

	ctag	*cp=0;

	if(mThis) {
		cp = room->first_ply;
		while(cp) {
			if(mThis->isEnmCrt(cp->crt->name))
				return(true);
			cp = cp->next_tag;
		}

		cp = room->first_mon;
		while(cp) {
			if(mThis->isEnmCrt(cp->crt->name))
				return(true);
			cp = cp->next_tag;
		}

	} else {

		cp = room->first_mon;
		while(cp) {
			if(	cp->crt->getConstMonster()->isEnmCrt(name) &&
				(!target || cp->crt != target) &&
				(countPets || !cp->crt->isPet())
			)
				return(true);

			cp = cp->next_tag;
		}

	}

	return(false);
}

BaseRoom *Creature::getRoom() const {
	if(parent_rom)
		return(parent_rom);
	return(area_room);
}

bstring Creature::fullName() const {
	const Player *player = getConstPlayer();
	bstring str = name;

	if(player && player->flagIsSet(P_CHOSEN_SURNAME)) {
		str += " ";
		str += player->getSurname();
	}

	return(str);
}

void Creature::unmist() {
	if(isMonster())
		return;
	if(!flagIsSet(P_MISTED))
		return;

	clearFlag(P_MISTED);
	clearFlag(P_SNEAK_WHILE_MISTED);
	unhide();

	printColor("^mYou return to your natural form.\n");
	if(getRoom())
		broadcast(getSock(), getRoom(), "%M reforms.", this);
}

bool Creature::unhide(bool show) {
	if(isMonster()) {
		if(!flagIsSet(M_HIDDEN))
			return(false);

		clearFlag(M_HIDDEN);
		setFlag(M_WAS_HIDDEN);
	} else {
		if(!flagIsSet(P_HIDDEN))
			return(false);

		clearFlag(P_HIDDEN);

		if(show)
			printColor("^cYou have become unhidden.\n");
	}
	return(true);
}

Realm Monster::getBaseRealm() const {
	return(baseRealm);
}

void Monster::setBaseRealm(Realm toSet) {
	baseRealm = toSet;
}

void Creature::convertOldFlags() {
}

bool Creature::convertFlag(int flag) {
	if(flagIsSet(flag)) {
		clearFlag(flag);
		return(true);
	}
	return(false);
}


//*********************************************************************
//						hasMp
//*********************************************************************

bool Creature::hasMp() const {
	return(mp.getMax() != 0 && cClass != BERSERKER && cClass != LICH);
}

//*********************************************************************
//						getCrtStr
//*********************************************************************

bstring Creature::getCrtStr(const Creature* viewer, int flags, int num) const {
	std::ostringstream crtStr;
	bstring toReturn = "";
	char ch;
	int mobNum=0;
	//	char	*str;

	if(!this)
		return("(ERROR: NULL CRT)");

	flags |= viewer->displayFlags();
	const Player* pThis = getConstPlayer();
	// Player
	if(isPlayer()) {
		// Target is possessing a monster -- Show the monsters name if invis
		if(flagIsSet(P_ALIASING) && flagIsSet(P_DM_INVIS)) {
			if(!pThis->getAlias()->flagIsSet(M_NO_PREFIX)) {
				crtStr << "A " << pThis->getAlias()->name;
			} else
				crtStr << pThis->getAlias()->name;
		}
		// Target is a dm, is dm invis, and viewer is not a dm       OR
		// Target is a ct, is dm invis, and viewer is not a dm or ct OR
		// Target is staff less than a ct and is dm invis, viewier is less than a builder
		else if((cClass == DUNGEONMASTER && flagIsSet(P_DM_INVIS) && !(flags & ISDM) ) ||
				 (cClass == CARETAKER && (flagIsSet(P_DM_INVIS) && !(flags & ISDM) && !(flags & ISCT))) ||
				 (flagIsSet(P_DM_INVIS) && !(flags & ISDM) && !(flags & ISCT) && !(flags & ISBD))  )
		{
			crtStr << "Someone";
		}
		// Target is misted, viewer can't detect mist, or isn't staff
		else if( flagIsSet(P_MISTED) && !(flags & MIST) && !(flags & ISDM) && !(flags & ISCT) && !(flags & ISBD)) {
			crtStr << "A light mist";
		}
		// Target is invisible and viewer doesn't have detect-invis or isn't staff
		else if(isInvisible() && !(flags & INV) && !(flags & ISDM) && !(flags & ISCT) && !(flags & ISBD)) {
			crtStr << "Someone";
		}
		// Can be seen
		else {
			crtStr << name;
			if( flagIsSet(P_DM_INVIS ) )
				crtStr << " (+)";
			// Invis
			else if(isInvisible())
				crtStr << " (*)";
			// Misted
			else if(flagIsSet(P_MISTED))
				crtStr << " (m)";
		}
		toReturn = crtStr.str();
		return(toReturn);
	}

	// Monster
	// Target is a monster, is invisible, and viewer doesn't have detect-invis or is not staff
	if(isMonster() && isInvisible() && !(flags & INV) && !(flags & ISDM) && !(flags & ISCT) && !(flags & ISBD)) {
		crtStr << "Something";
	} else {
		if(num == 0) {
			if(!flagIsSet(M_NO_PREFIX)) {
				crtStr << "the ";
				if(!(flags & NONUM)) {
					mobNum = ((Monster*)this)->getNumMobs();
					if(mobNum>1) {
						crtStr << getOrdinal(mobNum).c_str();
						crtStr << " ";
					}
				}
				crtStr << name;
			} else
				crtStr << name;
		} else if(num == 1) {
			if(flagIsSet(M_NO_PREFIX))
				crtStr << "";
			else {
				ch = low(name[0]);
				if(ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u')
					crtStr << "an ";
				else
					crtStr << "a ";
			}
			crtStr << name;
		} else {
			char tempStr[2056];
			strcpy(tempStr, int_to_text(num));
			strcat(tempStr, " ");
			strcat(tempStr, name);
			if(flagIsSet(M_MAN_TO_MEN)) {
				tempStr[strlen(tempStr)-2] = 'e';
			} else if(!flagIsSet(M_NO_S_ON_PLURAL)) {
				tempStr[strlen(tempStr)+1] = 0;
				tempStr[strlen(tempStr)+2] = 0;
				if(tempStr[strlen(tempStr)-1] == 's' || tempStr[strlen(tempStr)-1] == 'x') {
					tempStr[strlen(tempStr)] = 'e';
					tempStr[strlen(tempStr)] = 's';
				} else {
					if(flagIsSet(M_F_TO_VE_ON_PLURAL)) {
						strcat(tempStr, "s");
						tempStr[strlen(tempStr)-2] = 'v';
						tempStr[strlen(tempStr)-1] = 'e';
						tempStr[strlen(tempStr)] = 's';
					} else if(flagIsSet(M_Y_TO_IE_ON_PLURAL)) {
						strcat(tempStr, "s");
						tempStr[strlen(tempStr)-2] = 'i';
						tempStr[strlen(tempStr)-1] = 'e';
						tempStr[strlen(tempStr)] = 's';
					} else
						tempStr[strlen(tempStr)] = 's';
				}
			}
			crtStr << tempStr;
		}
		if(flagIsSet(M_IRREGULAR_PLURAL) && num > 1) {
			int     found;
			FILE    *plural;
			char    pform[80];
			char    sform[80];
			char    pfile[80];

			found = 0;
			sprintf(pfile, "%s/plurals.txt", GAMEPATH);

			plural = fopen(pfile, "r");
			if(plural != NULL) {
				while(!found && !(feof (plural))) {
					fflush(plural);
					// get singular form
					fgets(sform, sizeof(sform), plural);
					sform[strlen(sform)-1] = 0;
					if(sform[strlen(sform)-1] == '\r')
						sform[strlen(sform)-1] = 0;
					fflush(plural);
					// get plural form
					fgets(pform, sizeof(pform), plural);
					pform[strlen(pform)-1] = 0;
					if(pform[strlen(pform)-1] == '\r')
						pform[strlen(pform)-1] = 0;

					if(strcmp(name, sform) == 0) {
						if(num < 21)
							crtStr << int_to_text(num);
						crtStr << " " ;
						crtStr << pform;
						found = 1;
					}
				}
				fclose(plural);
			}
		}


		// Target is magic, and viewer has detect magic on
		if((flags & MAG) && (isMonster()) && (flagIsSet(M_CAN_CAST)))
			crtStr << " (M)";
	}
	toReturn = crtStr.str();
	if(flags & CAP)
		toReturn[0] = up(toReturn[0]);
	return(toReturn);
}

//*********************************************************************
//						setSkill
//*********************************************************************

bool Creature::setSkill(const bstring skillStr, int gained) {
	if(!gConfig->skillExists(skillStr))
		return(false);

	CrtSkill* crSkill = getSkill(skillStr); //= new CrtSkill(skillStr, cmnd->val[4]);
	if(crSkill)
		crSkill->setGained(gained);
	else  {
		crSkill = new CrtSkill(skillStr, gained);
		skills[skillStr] = crSkill;
	}

	return(true);
}

//*********************************************************************
//						isGroupLeader
//*********************************************************************
// Are we a group leader against the given monster

bool Creature::isGroupLeader(Monster* target) {
	if(isMonster())
		return(false);
	ctag *cp = first_fol;
	Creature *crt;
	while(cp) {
		crt = cp->crt;
		if(crt && crt->getsGroupExperience(target))
			return(true);
		cp = cp->next_tag;
	}
	return(false);
}

//*********************************************************************
//						getsGroupExperience
//*********************************************************************

bool Creature::getsGroupExperience(Monster* target) {
	// We can get exp if we're a player...
	return(isPlayer() &&
		// And idle less than 2 minutes
		getPlayer()->getIdle() < 120 &&
		// And we haven't abused group exp
		!flagIsSet(P_GROUP_EXP_ABUSE) &&
		// And we're not a DM invis person
		!flagIsSet(P_DM_INVIS) &&
		// And we are visible! (No more clerics/mages sitting invis leeching)
		!isInvisible() &&
		// No invis players
		!flagIsSet(P_HIDDEN) &&
		// No mists either
		!flagIsSet(P_MISTED) &&
		// no self-declared AFK people
		!flagIsSet(P_AFK) &&
		// no unconscious people
		!flagIsSet(P_UNCONSCIOUS) &&
		// no statues
		!isEffected("petrification") &&
		// and they're on the enemy list
		target->isEnmCrt(this->name)
	);
}

//*********************************************************************
//						doesntBreathe
//*********************************************************************

bool Creature::doesntBreathe() const {
	return(	(monType::noLivingVulnerabilities(type) || isUndead()) &&
			!isEffected("vampirism") // vampires breathe (and can drown)
	);
}

//*********************************************************************
//						immuneCriticals
//*********************************************************************

bool Creature::immuneCriticals() const {
	return(monType::immuneCriticals(type));
}

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

const char* Creature::getName() {
	return(name);
}

//*********************************************************************
//						getSock
//*********************************************************************

Socket* Creature::getSock() const {
	return(NULL);
}

//*********************************************************************
//						getSexName
//*********************************************************************

bstring getSexName(Sex sex) {
	if(sex == SEX_FEMALE)
		return("Female");
	if(sex == SEX_MALE)
		return("Male");
	if(sex == SEX_NONE)
		return("Genderless");
	return("Unknown");
}

//*********************************************************************
//						getDisplayRace
//*********************************************************************

unsigned short Creature::getDisplayRace() const {
	if(isMonster() || !isEffected("illusion"))
		return(race);
	return(getEffect("illusion")->getExtra());
}

//*********************************************************************
//						canSpeak
//*********************************************************************

bool Creature::canSpeak() const {
	if(isStaff())
		return(true);
	if(isEffected("silence"))
		return(false);
	if(getRoom()->isEffected("globe-of-silence"))
		return(false);
	return(true);
}


Creature* Creature::addTarget(Creature* toTarget) {
	if(!toTarget)
		return(NULL);

	// We've already got them targetted!
	if(toTarget == myTarget)
		return(myTarget);

	clearTarget();

	toTarget->addTargetingThis(this);
	myTarget = toTarget;

	Player* ply = getPlayer();
	if(ply) {
		ply->printColor("You are now targeting %s.\n", myTarget->getName());
	}

	return(myTarget);

}
void Creature::addTargetingThis(Creature* targeter) {
	ASSERTLOG(targeter);

	Player* ply = getPlayer();
	if(ply) {
		ply->printColor("%s is now targeting you!\n", targeter->getName());
	}
	targetingThis.push_back(targeter);
}

void Creature::clearTarget(bool clearTargetsList) {
	if(!myTarget)
		return;

	Player* ply = getPlayer();
	if(ply) {
		ply->printColor("You are no longer targeting %s!\n", myTarget->getName());
	}

	if(clearTargetsList)
		myTarget->clearTargetingThis(this);

	myTarget = NULL;

	return;
}

void Creature::clearTargetingThis(Creature* targeter) {
	ASSERTLOG(targeter);

	Player* ply = getPlayer();
	if(ply) {
		ply->printColor("%s is no longer targeting you!\n", targeter->getName());
	}

	targetingThis.remove(targeter);
}




int cmdTarget(Player* player, cmd* cmnd) {
	if(cmnd->num < 2) {
		player->print("You are targetting: ");
		if(player->myTarget)
			player->print("%s\n", player->myTarget->getName());
		else
			player->print("Noone!\n");

		//if(player->isCt()) {
		{
			player->print("People targeting you: ");
			Creature* targetter;
			int numTargets = 0;
			foreach(targetter, player->targetingThis) {
				if(numTargets++ != 0)
					player->print(", ");
				player->print("%s", targetter->getName());
			}
			if(numTargets == 0)
				player->print("Nobody!");
			player->print("\n");
		}
		return(0);
	}

	if(!strcasecmp(cmnd->str[1], "-c")) {
		player->print("Clearing target.\n");
		player->clearTarget();
		return(0);
	}

	lowercize(cmnd->str[1], 1);

	Creature* toTarget = player->getRoom()->findCreature(player, cmnd);
	if(!toTarget) {
		player->print("You don't see that here.\n");
		return(0);
	}
	player->addTarget(toTarget);

	return(0);
}


Creature* Creature::getTarget() {
	return(myTarget);
}

bool Creature::hasAttackableTarget() {
	return(getTarget() && getTarget() != this && inSameRoom(getTarget()) && canSee(getTarget()));
}

bool Creature::inSameRoom(Creature* target) {
	return(target && target->getRoom() == getRoom());
}