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/
/*
 * effects.cpp
 *   Effects on creatures
 *   ____            _
 *  |  _ \ ___  __ _| |_ __ ___  ___
 *  | |_) / _ \/ _` | | '_ ` _ \/ __|
 *  |  _ <  __/ (_| | | | | | | \__ \
 *  |_| \_\___|\__,_|_|_| |_| |_|___/
 *
 * 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
 *
 */
#include "mud.h"
#include "effects.h"
#include "commands.h"
// C++ includes
#include <iomanip>
#include <locale>


//*********************************************************************
//						getParentType
//*********************************************************************

EffectParentType Effects::getParentType(Creature* cParent, BaseRoom* rParent, Exit *xParent) {
	if(xParent)
		return(EFFECT_EXIT);
	if(cParent)
		return(EFFECT_CREATURE);
	// rParent is also set for Exits, so check this last
	if(rParent)
		return(EFFECT_ROOM);
	return(EFFECT_NO_PARENT);
}

//*********************************************************************
//						EffectInfo
//*********************************************************************

EffectInfo::EffectInfo(bstring pName, time_t pLastMod, long pDuration, int pStrength, Creature* cParent, BaseRoom* rParent, Exit* xParent, const Creature* owner) {
	myEffect = findEffect(pName, Effects::getParentType(cParent, rParent, xParent));
	if(!myEffect)
		throw bstring("Can't find effect " + pName);
	name = pName;
	setOwner(owner);
	lastMod = pLastMod;
	duration = pDuration;
	strength = pStrength;
	extra = 0;

	parentCreature = cParent;
	parentRoom = rParent;
	parentExit = xParent;
}

EffectInfo::EffectInfo() {
	parentCreature = 0;
	parentRoom = 0;
	myEffect = 0;
	lastMod = 0;
	duration = 0;
	strength = 0;
	extra = 0;
}

EffectInfo::EffectInfo(xmlNodePtr rootNode, EffectParentType type) {
	xmlNodePtr curNode = rootNode->children;
	extra = 0;
	duration = 0;
	strength = 0;
	while(curNode) {
			if(NODE_NAME(curNode, "Name")) xml::copyToBString(name, curNode);
		else if(NODE_NAME(curNode, "Duration")) xml::copyToNum(duration, curNode);
		else if(NODE_NAME(curNode, "Strength")) xml::copyToNum(strength, curNode);
		else if(NODE_NAME(curNode, "Extra")) xml::copyToNum(extra, curNode);

		curNode = curNode->next;
	}
	lastMod = time(0);
	myEffect = findEffect(name, type);
	if(!myEffect) {
		throw bstring("Can't find effect listing " + name);
	}
	parentCreature = 0;
	parentRoom = 0;
}

EffectInfo::~EffectInfo() {
}

AlcoholState getAlcoholState(const EffectInfo* effect) {
	if(!effect || effect->getStrength() < 1)
		return(ALCOHOL_SOBER);
	if(effect->getStrength() < 20)
		return(ALCOHOL_TIPSY);
	if(effect->getStrength() < 66)
		return(ALCOHOL_DRUNK);
	return(ALCOHOL_INEBRIATED);
}

void EffectInfo::setParentCreature(Creature* parent) { parentCreature = parent; }
void EffectInfo::setParentRoom(BaseRoom* parent) { parentRoom = parent; }
void EffectInfo::setParentExit(Exit* parent) { parentExit = parent; }
effectPtr EffectInfo::getEffect() const { return(myEffect); }
const bstring& EffectInfo::getName() const { return(name); }
bstring EffectInfo::getDisplayName() const {
	bstring displayName = myEffect->display;
	if(myEffect->name != "drunkenness")
		return(displayName);

	// drunkenness has a different name based on strength
	AlcoholState state = getAlcoholState(this);
	if(state == ALCOHOL_SOBER)
		displayName += "Sober";  // this state should never happen
	else if(state == ALCOHOL_TIPSY)
		displayName += "Tipsy";
	else if(state == ALCOHOL_DRUNK)
		displayName += "Drunk";
	else if(state == ALCOHOL_INEBRIATED)
		displayName += "Inebriated";

	displayName += "^x";
	return(displayName);
}
const bstring& EffectInfo::getOwner() const { return(pOwner); }
bool EffectInfo::isOwner(const Creature* owner) const {
	// currently, only players can own effects
	return(owner && owner->isPlayer() && pOwner == owner->name);
}
time_t EffectInfo::getLastMod() const { return(lastMod); }
long EffectInfo::getDuration() const { return(duration); }
int EffectInfo::getStrength() const { return(strength); }
int EffectInfo::getExtra() const { return(extra); }
bool EffectInfo::isPermanent() const { return(duration == -1); }
Creature* EffectInfo::getParentCreature() const { return(parentCreature); }
BaseRoom* EffectInfo::getParentRoom() const { return(parentRoom); }
Exit* EffectInfo::getParentExit() const { return(parentExit); }
void EffectInfo::setOwner(const Creature* owner) {
	if(owner)
		pOwner = owner->name;
	else
		pOwner = "";
}
void EffectInfo::setStrength(int pStrength) { strength = pStrength; }
void EffectInfo::setExtra(int pExtra) { extra = pExtra; }
void EffectInfo::setDuration(long pDuration) { duration = pDuration; }

//*********************************************************************
//						willOverWrite
//*********************************************************************
// Will the given effect overwrite the existing effect?

bool EffectInfo::willOverWrite(EffectInfo* existingEffect) const {
	// No effect, it'll overwrite :-P
	if(!existingEffect)
		return(true);

	// Perm effects take presedence
	if(duration == -1 && existingEffect->duration != -1)
		return(true);

	if(strength < existingEffect->strength)
		return(false);

	// Don't overwrite perm effects with non perm
	if(existingEffect->duration == -1 && duration != -1)
		return(false);

	return(true);
}

//*********************************************************************
//						operator<<
//*********************************************************************

std::ostream& operator<<(std::ostream& out, const EffectInfo& eff) {
	out.setf(std::ios::right, std::ios::adjustfield);
	bstring display = eff.getDisplayName();

	short count=0;
	int len = display.getLength();
	for(int i=0; i<len; i++) {
		if(display.getAt(i) == '^') {
			count += 2;
			i++;
		}
	}
	out << std::setw(38+count) << display << " - ";

	if(eff.duration == -1)
		out << "Permanent!";
	else
		out << timeStr(eff.duration);

	return(out);
}

//*********************************************************************
//						pulse
//*********************************************************************
// True on a sucessful pulse
// False if it's time to wear off

bool EffectInfo::pulse(time_t t) {
	ASSERTLOG(parentCreature || parentRoom);

	bool wearOff = updateLastMod(t);
	if(wearOff)
		return(false);

	if(myEffect && (myEffect->effFn))
		return((*(myEffect->effFn))(this, parentCreature, EFFECT_PULSE, NULL, FROM_NOWHERE));
	return(false);
}

//*********************************************************************
//						updateLastMod
//*********************************************************************
// True if it's time for this effect to wear off

bool EffectInfo::updateLastMod(time_t t) {
	time_t diff = t - lastMod;
	lastMod = t;
	diff = MIN(MAX(0, duration), diff);
	duration -= diff;

	return(duration == 0);
}

//*********************************************************************
//						getRoom
//*********************************************************************

BaseRoom* EffectInfo::getRoom() const {
	if(parentCreature)
		return(parentCreature->getRoom());
	return(parentRoom);
}

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

bool EffectInfo::remove(bool show) {
	ASSERTLOG(parentCreature || parentRoom);

	if(myEffect && (myEffect->effFn)) {
		bool success = true;
		if(show) {
			if(parentCreature) {
				if(!myEffect->selfStrDel.empty())
					parentCreature->printColor("%s\n", myEffect->selfStrDel.c_str());
				if(!myEffect->roomStrDel.empty() && getRoom())
					broadcast(parentCreature->getSock(), getRoom(), myEffect->roomStrDel.c_str(), parentCreature);
			} else if(parentExit) {
				if(!myEffect->roomStrDel.empty() && getRoom())
					broadcast(0, getRoom(), myEffect->roomStrDel.c_str(), parentExit->name);
			} else {
				if(!myEffect->roomStrDel.empty() && getRoom())
					broadcast(0, getRoom(), myEffect->roomStrDel.c_str());
			}
		}
		success &= (*(myEffect->effFn))(this, parentCreature, EFFECT_UNAPPLY, NULL, FROM_NOWHERE);
		return(success);
	}
	return(false);
}

//*********************************************************************
//						compute
//*********************************************************************

bool EffectInfo::compute(void* applier, ApplyFrom aFrom) {
	ASSERTLOG(parentCreature || parentRoom);
	if(!myEffect || !(myEffect->effFn))
		return(false);
	return((*(myEffect->effFn))(this, parentCreature, EFFECT_COMPUTE, applier, aFrom));
}

//*********************************************************************
//						add
//*********************************************************************

bool EffectInfo::add() {
	ASSERTLOG(parentCreature || parentRoom);
	if(!myEffect || !(myEffect->effFn))
		return(false);
	if(parentCreature) {
		if(!myEffect->selfStrAdd.empty())
			parentCreature->printColor("%s\n", myEffect->selfStrAdd.c_str());
		if(!myEffect->roomStrAdd.empty() && getRoom())
			broadcast(parentCreature->getSock(), getRoom(), myEffect->roomStrAdd.c_str(), parentCreature);
	} else if(parentExit) {
		if(!myEffect->roomStrAdd.empty() && getRoom())
			broadcast(0, getRoom(), myEffect->roomStrAdd.c_str(), parentExit->name);
	} else {
		if(!myEffect->roomStrAdd.empty() && getRoom())
			broadcast(0, getRoom(), myEffect->roomStrAdd.c_str());
	}

	return(true);
}

//*********************************************************************
//						apply
//*********************************************************************

bool EffectInfo::apply() {
	ASSERTLOG(parentCreature || parentRoom);
	if(!myEffect || !(myEffect->effFn))
		return(false);
	return((*(myEffect->effFn))(this, parentCreature, EFFECT_APPLY, NULL, FROM_NOWHERE));
}

// End - EffectInfo functions


//*********************************************************************
//						addEffect
//*********************************************************************

bool Creature::addEffect(const bstring& effect, void* applier, ApplyFrom aFrom, bool show, const Creature* owner) {
	return(effects.addEffect(effect, applier, aFrom, show, this, 0, 0, owner));
}
bool BaseRoom::addEffect(const bstring& effect, void* applier, ApplyFrom aFrom, bool show, const Creature* owner) {
	return(effects.addEffect(effect, applier, aFrom, show, 0, this, 0, owner));
}
bool Exit::addEffect(const bstring& effect, void* applier, ApplyFrom aFrom, bool show, BaseRoom* rParent, const Creature* owner) {
	return(effects.addEffect(effect, applier, aFrom, show, 0, rParent, this, owner));
}
bool Effects::addEffect(const bstring& effect, void* applier, ApplyFrom aFrom, bool show, Creature* cParent, BaseRoom* rParent, Exit* xParent, const Creature* owner) {
	bool success = true;
	EffectInfo* newEffect = new EffectInfo(effect, time(0), -1, 1, cParent, rParent, xParent, owner);
	// Compute the effects potency, see if it will overwrite, and then apply & add
	success = newEffect->compute(applier, aFrom);
	if(success)
		return(addEffect(newEffect, show, cParent, rParent, xParent));
	return(false);
}

//*********************************************************************
//						addEffect
//*********************************************************************

bool Creature::addEffect(const bstring& effect, long duration, int strength, bool show, const Creature* owner) {
	return(effects.addEffect(effect, duration, strength, show, this, 0, 0, owner));
}
bool BaseRoom::addEffect(const bstring& effect, long duration, int strength, bool show, const Creature* owner) {
	return(effects.addEffect(effect, duration, strength, show, 0, this, 0, owner));
}
bool Exit::addEffect(const bstring& effect, long duration, int strength, bool show, BaseRoom* rParent, const Creature* owner) {
	return(effects.addEffect(effect, duration, strength, show, 0, rParent, this, owner));
}
bool Effects::addEffect(const bstring& effect, long duration, int strength, bool show, Creature* cParent, BaseRoom* rParent, Exit* xParent, const Creature* owner) {
	if(!findEffect(effect, getParentType(cParent, rParent, xParent)))
		return(false);
	EffectInfo* newEffect = new EffectInfo(effect, time(0), duration, strength, cParent, rParent, xParent, owner);

	return(addEffect(newEffect, show, cParent, rParent, xParent));
}

//*********************************************************************
//						addEffect
//*********************************************************************

bool Creature::addEffect(EffectInfo* newEffect, bool show) {
	return(effects.addEffect(newEffect, show, this));
}
bool BaseRoom::addEffect(EffectInfo* newEffect, bool show) {
	return(effects.addEffect(newEffect, show, 0, this));
}
bool Exit::addEffect(EffectInfo* newEffect, bool show, BaseRoom* rParent) {
	return(effects.addEffect(newEffect, show, 0, rParent, this));
}
bool Effects::addEffect(EffectInfo* newEffect, bool show, Creature* cParent, BaseRoom* rParent, Exit* xParent) {
	newEffect->setParentCreature(cParent);
	newEffect->setParentRoom(rParent);
	newEffect->setParentExit(xParent);

	EffectInfo* oldEffect = getEffect(newEffect->getName());
	bool success = true;

	if(oldEffect && !newEffect->willOverWrite(oldEffect)) {
		// The new effect won't overwrite, so don't add it
		if(cParent)
			cParent->print("The effect didn't take hold.\n");
		delete newEffect;
		return(false);
	}

	// If no existing effect, or this one will overwrite remove the old one, and add the new one
	removeEffect(newEffect->getName(), false, true, cParent, rParent, xParent);		// Don't show the removal
	if(show)
		newEffect->add();
	success &= newEffect->apply();
	list.push_back(newEffect);
	if(rParent)
		rParent->addEffectsIndex();
	return(true);
}

//*********************************************************************
//						addPermEffect
//*********************************************************************

bool Creature::addPermEffect(const bstring& effect, int strength, bool show) {
	return(effects.addEffect(effect, -1, strength, show, this));
}
bool BaseRoom::addPermEffect(const bstring& effect, int strength, bool show) {
	return(effects.addEffect(effect, -1, strength, show, 0, this));
}
bool Exit::addPermEffect(const bstring& effect, int strength, bool show, BaseRoom* rParent) {
	return(effects.addEffect(effect, -1, strength, show, 0, rParent, this));
}

//*********************************************************************
//						removeEffect
//*********************************************************************
// Remove the effect (Won't remove permanent effects if remPerm is false)

bool Creature::removeEffect(const bstring& effect, bool show, bool remPerm) {
	return(effects.removeEffect(effect, show, remPerm, this));
}
bool BaseRoom::removeEffect(const bstring& effect, bool show, bool remPerm) {
	return(effects.removeEffect(effect, show, remPerm, 0, this));
}
bool Exit::removeEffect(const bstring& effect, bool show, bool remPerm, BaseRoom* rParent) {
	return(effects.removeEffect(effect, show, remPerm, 0, rParent, this));
}
bool Effects::removeEffect(const bstring& effect, bool show, bool remPerm, Creature* cParent, BaseRoom* rParent, Exit* xParent) {
	EffectInfo* toDel = getEffect(effect);
	if(toDel && (toDel->getDuration() != -1 || (toDel->getDuration() == -1 && remPerm)))
		return(removeEffect(toDel, show, cParent, rParent, xParent));
	return(false);
}

//*********************************************************************
//						removeEffect
//*********************************************************************

bool Creature::removeEffect(EffectInfo* toDel, bool show) {
	return(effects.removeEffect(toDel, show, this));
}
bool BaseRoom::removeEffect(EffectInfo* toDel, bool show) {
	return(effects.removeEffect(toDel, show, 0, this));
}
bool Exit::removeEffect(EffectInfo* toDel, bool show, BaseRoom* rParent) {
	return(effects.removeEffect(toDel, show, 0, rParent, this));
}
bool Effects::removeEffect(EffectInfo* toDel, bool show, Creature* cParent, BaseRoom* rParent, Exit* xParent) {
	if(!toDel)
		return(false);
	ASSERTLOG(toDel->getParentCreature() == cParent);
	ASSERTLOG(toDel->getParentRoom() == rParent);
	ASSERTLOG(toDel->getParentExit() == xParent);
	list.remove(toDel);
	toDel->remove(show);
	delete toDel;
	return(true);
}

//*********************************************************************
//						removeOwner
//*********************************************************************
// on suicide, we remove the owner of the effect

void Effects::removeOwner(const Creature* owner) {
	std::list<EffectInfo*>::iterator it;

	for(it = list.begin() ; it != list.end() ; it++) {
		if((*it)->isOwner(owner))
			(*it)->setOwner(0);
	}
}

//*********************************************************************
//						isEffected
//*********************************************************************

bool Creature::isEffected(const bstring& effect) const {
	return(effects.getEffect(effect) != NULL);
}
bool BaseRoom::isEffected(const bstring& effect) const {
	return(effects.getEffect(effect) != NULL);
}
bool Exit::isEffected(const bstring& effect) const {
	return(effects.getEffect(effect) != NULL);
}

//*********************************************************************
//						hasPermEffect
//*********************************************************************

bool Creature::hasPermEffect(const bstring& effect) const {
	EffectInfo* toCheck = effects.getEffect(effect);
	return(toCheck && toCheck->getDuration() == -1);
}
bool BaseRoom::hasPermEffect(const bstring& effect) const {
	EffectInfo* toCheck = effects.getEffect(effect);
	return(toCheck && toCheck->getDuration() == -1);
}
bool Exit::hasPermEffect(const bstring& effect) const {
	EffectInfo* toCheck = effects.getEffect(effect);
	return(toCheck && toCheck->getDuration() == -1);
}

//*********************************************************************
//						getEffect
//*********************************************************************

EffectInfo* Creature::getEffect(const bstring& effect) const {
	return(effects.getEffect(effect));
}
EffectInfo* BaseRoom::getEffect(const bstring& effect) const {
	return(effects.getEffect(effect));
}
EffectInfo* Exit::getEffect(const bstring& effect) const {
	return(effects.getEffect(effect));
}
EffectInfo* Effects::getEffect(const bstring& effect) const {
	std::list<EffectInfo*>::const_iterator eIt;
	for(eIt = list.begin() ; eIt != list.end() ; eIt++) {
		if((*eIt) && (*eIt)->getName() == effect)
			return((*eIt));
	}
	return(NULL);
}

//*********************************************************************
//						pulseEffects
//*********************************************************************
// Pulse all effects on this creature
// return false if creature died because of this

bool Creature::pulseEffects(time_t t) {
	bool pulsed = true;
	bool poison = false;
	EffectInfo* effect=0;
	std::list<EffectInfo*>::iterator eIt;
	deathtype = DT_NONE;
	for(eIt = effects.list.begin() ; eIt != effects.list.end() ;) {
		effect = (*eIt);
		// Pulse!

		ASSERTLOG(effect->getParentCreature() == this);
		pulsed = effect->pulse(t);

		// If pulse returns false, purge this effect
		if(!pulsed) {
			effect->remove();
			if(poison || effect->isPoison())
				poison = true;
			delete effect;
			eIt = effects.list.erase(eIt);
		} else
			eIt++;
	}

	// pulse effects might kill them
	if(deathtype != DT_NONE && hp.getCur() < 1) {
		if(isPlayer())
			getPlayer()->die(deathtype);
		else
			getMonster()->mobDeath();
		return(false);
	}

	// if they're not poisoned anymore, clear poison
	if(poison && !isPoisoned())
		curePoison();

	return(true);
}

//*********************************************************************
//						pulseEffects
//*********************************************************************

bool BaseRoom::pulseEffects(time_t t) {
	effects.pulse(t, this);

	xtag* xp = first_ext;
	while(xp) {
		xp->ext->pulseEffects(t, this);
		xp = xp->next_tag;
	}
	return(true);
}

//*********************************************************************
//						pulseEffects
//*********************************************************************

bool Exit::pulseEffects(time_t t, BaseRoom* rParent) {
	effects.pulse(t, rParent, this);
	return(true);
}

//*********************************************************************
//						pulse
//*********************************************************************
// generic pulse function that can be used on rooms and exits (because
// they can't die like players can)

void Effects::pulse(time_t t, BaseRoom* rParent, Exit* xParent) {
	std::list<EffectInfo*>::iterator it;
	EffectInfo* effect=0;
	bool pulsed=false;

	for(it = list.begin() ; it != list.end() ;) {
		effect = (*it);
		// Pulse!

		ASSERTLOG(effect->getParentRoom() == rParent);
		ASSERTLOG(effect->getParentExit() == xParent);
		pulsed = effect->pulse(t);

		// If pulse returns false, purge this effect
		if(!pulsed) {
			effect->remove();
			delete effect;
			it = list.erase(it);
		} else
			it++;
	}
}

//*********************************************************************
//						removeAll
//*********************************************************************

void Effects::removeAll() {
	EffectInfo* effect=0;
	std::list<EffectInfo*>::iterator eIt;
	for(eIt = list.begin() ; eIt != list.end() ; eIt++) {
		effect = (*eIt);
		delete effect;
		(*eIt) = NULL;
	}
	list.clear();
}

//*********************************************************************
//						copy
//*********************************************************************

void Effects::copy(const Effects* source, Creature* cParent) {
	EffectInfo* effect;
	std::list<EffectInfo*>::const_iterator eIt;
	for(eIt = source->list.begin() ; eIt != source->list.end() ; eIt++) {
		effect = new EffectInfo();
		(*effect) = *(*eIt);
		effect->setParentCreature(cParent);
		list.push_back(effect);
	}
}

//*********************************************************************
//						cmdEffects
//*********************************************************************

int cmdEffects(Creature* creature, cmd* cmnd) {
	Creature* target = creature;
	int num=0;

	if(creature->isCt()) {
		if(cmnd->num > 1) {
			target = creature->getRoom()->findCreature(creature, cmnd);
			cmnd->str[1][0] = up(cmnd->str[1][0]);

			if(!target) {
				target = gServer->findPlayer(cmnd->str[1]);

				if(!target || !creature->canSee(target)) {
					creature->print("Target not found.\n");
					return(0);
				}
			}
		}
	}

	num = target->effects.list.size();
	creature->print("Current Effects for %s:\n", target->name);
	creature->printColor("%s", target->effects.getEffectsString(creature).c_str());
	creature->print("\n%d effect%s found.\n", num, num != 1 ? "s" : "");
	return(0);
}

//*********************************************************************
//						getEffectsList
//*********************************************************************
// Return a list of effects

bstring Effects::getEffectsList() const {
	std::ostringstream effStr;

	effStr << "Effects: ";

	int num = 0;
	const EffectInfo* effect;
	std::list<EffectInfo*>::const_iterator eIt;
	for(eIt = list.begin() ; eIt != list.end() ; eIt++) {
		effect = (*eIt);
		if(num != 0)
			effStr << ", ";
		effStr << effect->getName();
		num++;
	}

	if(num == 0)
		effStr << "None";
	effStr << ".\n";

	bstring toPrint = effStr.str();

	return(toPrint);
}

//*********************************************************************
//						getEffectsString
//*********************************************************************
// Used to print out what effects a creature is under

bstring Effects::getEffectsString(const Creature* viewer) {
	std::ostringstream effStr;
	long t = time(0);

	EffectInfo* effect=0;
	std::list<EffectInfo*>::iterator eIt;
	for(eIt = list.begin() ; eIt != list.end() ; eIt++) {
		effect = (*eIt);
		effect->updateLastMod(t);
		effStr << *effect;
		if(viewer->isStaff()) {
			effStr << " ^WStrength: " << effect->getStrength();
			if(effect->getExtra())
				effStr << " ^WExtra: " << effect->getExtra();
		}
		effStr << "\n";
	}

	return(effStr.str());
}

//*********************************************************************
//						convertOldEffects
//*********************************************************************
// This function will convert flag/lt combos into effects

void Creature::convertOldEffects() {
	Player* pPlayer = getPlayer();
	Monster* mMonster = getMonster();
	if(version < "2.40") {
		if(mMonster) {
//			mMonster->convertToEffect("stoneskin", OLD_M_STONESKIN, -1);
//			mMonster->convertToEffect("invisibility", OLD_M_INVISIBLE, OLD_LT_INVISIBILITY);
		} else if(pPlayer) {

		}
	}
}

//*********************************************************************
//						convertToEffect
//*********************************************************************
// Convert the given effect from a flag/lt to an effect

bool Creature::convertToEffect(const bstring& effect, int flag, int lt) {
	if(!flagIsSet(flag))
		return(false);

	clearFlag(flag);


	long duration = 0;
	if(lt != -1 && lasttime[lt].interval != 0)
		duration = lasttime[lt].interval;
	else
		duration = -1;

	EffectInfo* newEffect = new EffectInfo(effect, time(0), duration, 1, this);

//	if(lt != -1 && (effect == "armor" || effect == "stoneskin")) {
//		newEffect->setStrength(lasttime[lt].misc);
//	}

	// Assuming that they're already properly under the effect, so just add it to the list
	// and don't actually add it or compute it.
	// IE: Strength buff -- they already have +str, so don't give them more str!!
	effects.list.push_back(newEffect);
	return(true);
}

//*********************************************************************
//						removeOppositeEffect
//*********************************************************************

bool Creature::removeOppositeEffect(const EffectInfo *effect) {
	return(effects.removeOppositeEffect(effect, this));
}
bool BaseRoom::removeOppositeEffect(const EffectInfo *effect) {
	return(effects.removeOppositeEffect(effect, 0, this));
}
bool Exit::removeOppositeEffect(const EffectInfo *effect, BaseRoom* rParent) {
	return(effects.removeOppositeEffect(effect, 0, rParent, this));
}
bool Effects::removeOppositeEffect(const EffectInfo *effect, Creature* cParent, BaseRoom* rParent, Exit* xParent) {
	effectPtr parentEffect = effect->getEffect();
	if(!parentEffect)
		return(false);

	if(parentEffect->oppositeEffect.empty())
		return(false);

	return(removeEffect(parentEffect->oppositeEffect, true, true, cParent, rParent, xParent));
}

//*********************************************************************
//						addStatModEffect
//*********************************************************************

bool Creature::addStatModEffect(EffectInfo* effect) {
	Stat* stat=0;
	Player* pThis = getPlayer();
	bool good;
	int hpMod = 0;
	int mpMod = 0;

	if(effect->getName() == "strength") {
		if(pThis) {
			if(flagIsSet(P_BERSERKED))
				pThis->loseRage();
			if(cClass == DEATHKNIGHT && flagIsSet(P_PRAYED))
				pThis->losePray();
		}
		good = true;
		stat = &strength;
	} else if(effect->getName() == "enfeeblement") {
		good = false;
		stat = &strength;
	} else if(effect->getName() == "haste") {
		if(pThis && flagIsSet(P_FRENZY))
			pThis->loseFrenzy();
		good = true;
		stat = &dexterity;
	} else if(effect->getName() == "slow") {
		good = false;
		stat = &dexterity;
	} else if(effect->getName() == "insight") {
		if(pThis && isEffected("confusion"))
			pThis->removeEffect("confusion");
		good = true;
		mpMod = (int)(level * 1.5);
		stat = &intelligence;
	} else if(effect->getName() == "feeblemind") {
		good = false;
		mpMod = (int)(level * -1.5);
		stat = &intelligence;
	} else if(effect->getName() == "prayer") {
		if(pThis && cClass != DEATHKNIGHT && flagIsSet(P_PRAYED))
			pThis->losePray();
		good = true;
		stat = &piety;
	} else if(effect->getName() == "damnation") {
		good = false;
		stat = &piety;
	} else if(effect->getName() == "fortitude") {
		good = true;
		hpMod = (int)(level * 1.5);
		stat = &constitution;
	} else if(effect->getName() == "weakness") {
		good = false;
		hpMod = (int)(level * -1.5);
		stat = &constitution;
	} else {
		print("Unknown stat effect: %s\n", effect->getName().c_str());
		return(false);
	}

	int addAmt = effect->getStrength();
	if(good == false && addAmt > 0)
		addAmt *= -1;

//	print("StatAdd: %s PreAdjust: %d", effect->getName().c_str(), addAmt);
	if(stat->getCur() + addAmt > MAX_STAT_NUM)
		addAmt = MAX(0, MAX_STAT_NUM - stat->getCur());
	else if(stat->getCur() + addAmt < 1)
		addAmt = 0 - (stat->getCur() - 1);
//	print(" PostAdjust: %d\n", addAmt);
	effect->setStrength(addAmt);

	stat->addCur(addAmt);

	 if(hpMod) {
		hpMod = hp.adjustMax(hpMod);
		effect->setExtra(hpMod);
		if(hpMod > 0)
			hp.adjust(hpMod);
	 } else if(mpMod) {
		mpMod = mp.adjustMax(mpMod);
		effect->setExtra(mpMod);
		if(mpMod > 0)
			mp.adjust(mpMod);
	}

	if(pThis) {
		pThis->computeAttackPower();
		pThis->computeAC();
	}
	return(true);
}

//*********************************************************************
//						remStatModEffect
//*********************************************************************

bool Creature::remStatModEffect(EffectInfo* effect) {
	Stat* stat=0;
	Player* pThis = getPlayer();
	int hpMod = 0;
	int mpMod = 0;

	if(effect->getName() == "strength") {
		stat = &strength;
	} else if(effect->getName() == "enfeeblement") {
		stat = &strength;
	} else if(effect->getName() == "haste") {
		stat = &dexterity;
	} else if(effect->getName() == "slow") {
		stat = &dexterity;
	} else if(effect->getName() == "insight") {
		mpMod = -1 * effect->getExtra();
		stat = &intelligence;
	} else if(effect->getName() == "feeblemind") {
		mpMod = -1 * effect->getExtra();
		stat = &intelligence;
	} else if(effect->getName() == "prayer") {
		stat = &piety;
	} else if(effect->getName() == "damnation") {
		stat = &piety;
	} else if(effect->getName() == "fortitude") {
		hpMod = -1 * effect->getExtra();
		stat = &constitution;
	} else if(effect->getName() == "weakness") {
		hpMod = -1 * effect->getExtra();
		stat = &constitution;
	} else {
		print("Unknown stat effect: %s\n", effect->getName().c_str());
		return(false);
	}

	int adjAmt = -1 * effect->getStrength();
//	if(good == false && adjAmt > 0)
//		adjAmt *= -1;
	if(stat->getCur() - adjAmt > MAX_STAT_NUM)
		adjAmt = MAX(0, MAX_STAT_NUM - stat->getCur());
	else if(stat->getCur() - adjAmt < 1)
		adjAmt = 0 - (stat->getCur() - 1);

	effect->setStrength(adjAmt);

	stat->adjust(adjAmt);
	if(hpMod) {
		hp.adjustMax(hpMod);
		if(hpMod > 0)
			hp.adjust(hpMod);
	} else if(mpMod) {
		mp.adjustMax(mpMod);
		if(mpMod > 0)
			mp.adjust(mpMod);
	}

	if(pThis) {
		pThis->computeAttackPower();
		pThis->computeAC();
	}
	return(true);
}

//*********************************************************************
//						exitEffectDamage
//*********************************************************************
// Wrapper to actually do the damage to the target
// Return: true if they were killed

bool exitEffectDamage(EffectInfo *effect, Creature* target, Creature* owner, Realm realm, DeathType dt, const char* crtStr, const char* deathStr, const char* roomStr, const char* killerStr) {
	Damage damage;

	if(!effect || effect->getExtra() || effect->isOwner(owner))
		return(false);

	Player* killer=0;
	bool online = true;

	if(effect->getOwner() != "") {
		killer = gServer->findPlayer(effect->getOwner());
		if(!killer) {
			if(loadPlayer(effect->getOwner().c_str(), &killer))
				online = false;
			else
				killer = 0;
		}
	}

	damage.set(mrand(effect->getStrength() / 2, effect->getStrength() * 3 / 2));
	target->modifyDamage(0, MAGICAL, damage, realm);

	if(killer && target->isMonster()) {
		target->getMonster()->addEnmCrt(killer);
		if(online)
			target->getMonster()->addEnmDmg(killer, damage.get());
	}

	target->printColor(crtStr, target->customColorize("*CC:DAMAGE*"), damage.get());

	target->hp.decrease(damage.get());
	if(target->hp.getCur() < 1) {
		target->print(deathStr);
		broadcast(target->getSock(), target->getRoom(), roomStr, target, target);

		if(killer) {
			if(online)
				killer->print(killerStr, target);
			target->die(killer);
			killer->save(online);
			if(!online)
				free_crt(killer);
		} else {
			if(target->isPlayer())
				target->getPlayer()->die(dt);
			else
				target->getMonster()->mobDeath();
		}
		return(true);
	}
	if(killer && !online)
		free_crt(killer);
	return(false);
}

//*********************************************************************
//						doEffectDamage
//*********************************************************************
// Return: true if they were killed

bool Exit::doEffectDamage(Creature* target) {
	Creature *owner = target;

	if(target->isPet())
		owner = target->following;

	if(	exitEffectDamage(
			getEffect("wall-of-fire"),
			target, owner, FIRE, BURNED,
			"The wall of fire burns you for %s%d^x damage.\n",
			"You are burned to death!\n",
			"%1M steps through the wall of fire.\n%M burns to death!",
			"%M steps through your wall of fire and is incinerated!\n"
	) )
		return(true);

	if(	exitEffectDamage(
			getEffect("wall-of-thorns"),
			target, owner, EARTH, THORNS,
			"The wall of thorns stabs you for %s%d^x damage.\n",
			"You are stabbed to death!\n",
			"%1M steps through a wall of thorns.\n%M is stabbed to death!",
			"%M steps through your wall of thorns and is stabbed to death!\n"
	) )
		return(true);

	return(false);
}