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

// C++ includes
#include <iomanip>
#include <locale>

//*********************************************************************
//						getDisplayName
//*********************************************************************

bstring EffectInfo::getDisplayName() const {
	bstring displayName = myEffect->getDisplay();
	if(myEffect->getName() != "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);
}

//*********************************************************************
//						getAlcoholState
//*********************************************************************

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);
}

//*********************************************************************
//						clearEffects
//*********************************************************************

void Config::clearEffects() {
	for(std::pair<bstring, Effect*> ep : effects) {
		delete ep.second;
	}
	effects.clear();
}

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

Effect* Config::getEffect(bstring eName) {
	std::map<bstring, Effect*>::const_iterator eIt;
	if( (eIt = effects.find(eName)) == effects.end())
		return(NULL);
	else
		return((*eIt).second);
}

//*********************************************************************
//						effectExists
//*********************************************************************

bool Config::effectExists(bstring eName) {
	return(effects.find(eName) != effects.end());
}

//*********************************************************************
//						dmEffectList
//*********************************************************************

int dmEffectList(Player* player, cmd* cmnd) {
	Effect* effect=0;
	bstring command = getFullstrText(cmnd->fullstr, 1);

	bool all = (command == "all");
	int id = command.toInt();

	player->printColor("^YEffects\n");
	player->printColor("Type ^y*effects all^x to see all effects or ^y*effects [num]^x to see a specific effect.\n");

    int i = 0;
    for(std::pair<bstring, Effect*> sp : gConfig->effects) {
    	effect = sp.second;
		i++;

		if(id != 0 && i != id)
			continue;

		player->printColor("%d)\tName: ^W%-20s^x   Use Str: %s^x    Display: %s\n", i,
			effect->getName().c_str(), effect->usesStrength() ? "^gY" : "^rN",
			effect->getDisplay().c_str());

		if(!all && i != id)
			continue;

		player->printColor("\tOpposite Effect: %s\n", effect->getOppositeEffect().c_str());
		player->printColor("\tSelfAddStr: %s^x\n", effect->getSelfAddStr().c_str());
		player->printColor("\tRoomAddStr: %s^x\n", effect->getRoomAddStr().c_str());
		player->printColor("\tSelfDelStr: %s^x\n", effect->getSelfDelStr().c_str());
		player->printColor("\tRoomDelStr: %s^x\n", effect->getRoomDelStr().c_str());
		player->printColor("\tPulsed: %s^x\n", effect->isPulsed() ? "^GPulsed" : "Non-Pulsed");
		if(effect->isPulsed())
		    *player << ColorOn << "\tPulse Delay: " << effect->getPulseDelay() << "^x\n" << ColorOff;
		player->printColor("\tSpell: %s^x\n", effect->isSpell() ? "^GYes" : "^RNo");
		player->printColor("\tType: %s^x\n", effect->getType().c_str());

		if(!effect->getApplyScript().empty())
			player->printColor("\tApply Script: %s\n", effect->getApplyScript().c_str());
		if(!effect->getPreApplyScript().empty())
			player->printColor("\tPre-Apply Script: %s\n", effect->getPreApplyScript().c_str());
		if(!effect->getPostApplyScript().empty())
			player->printColor("\tPost-Apply Script: %s\n", effect->getPostApplyScript().c_str());
   		if(!effect->getComputeScript().empty())
			player->printColor("\tCompute Script: %s\n", effect->getComputeScript().c_str());
   		if(!effect->getPulseScript().empty())
			player->printColor("\tPulse Script: %s\n", effect->getPulseScript().c_str());

   		if(!effect->getUnApplyScript().empty())
			player->printColor("\tUnApplyScript: %s\n", effect->getUnApplyScript().c_str());
	}

	return(0);
}

//*********************************************************************
//						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);

	// If the existing effect is due to an applier (currently only worn objects),
	// there's no way to override that effect.
	if(existingEffect->getApplier())
		return(false);

	// 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(myParent);

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

	if(myEffect->isPulsed()) {
		if(timeForPulse(t))
			return(runScript(myEffect->getPulseScript()));
	 }
	return(true);
}

//*********************************************************************
//						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;

	if(myApplier) {
		// for object appliers, keep the duration on the object in-sync with the effect duration
		Object* object = myApplier->getAsObject();
		if(object)
			object->setEffectDuration(duration);
	}

	return(duration == 0);
}

//*********************************************************************
//						timeForPulse
//*********************************************************************

bool EffectInfo::timeForPulse(time_t t) {
	time_t diff = t - lastPulse;
	if(diff < myEffect->getPulseDelay())
		return(false);

	lastPulse = t;
	return(true);
}
//*********************************************************************
//						remove
//*********************************************************************

bool EffectInfo::remove(bool show) {
	bool success = false;
	ASSERTLOG(myParent);

	if(myEffect) {
		success = true;
		if(show) {
			Creature* cParent = myParent->getAsCreature();
			if(cParent) {
				if(!myEffect->getSelfDelStr().empty())
					cParent->printColor("%s\n", myEffect->getSelfDelStr().c_str());
				if(!myEffect->getRoomDelStr().empty() && cParent->getRoomParent())
					cParent->getRoomParent()->effectEcho(myEffect->getRoomDelStr(), cParent);
			}
			Exit* xParent = myParent->getAsExit();
			if(xParent) {
				if(!myEffect->getRoomDelStr().empty()) {
					if(xParent->getRoom())
						xParent->getRoom()->effectEcho(myEffect->getRoomDelStr(), xParent);
					else
						std::cout << "Exit with no parent room!!!\n";
				}
			}
			BaseRoom* rParent = myParent->getAsRoom();
			if(rParent) {
				if(!myEffect->getRoomDelStr().empty())
					rParent->effectEcho(myEffect->getRoomDelStr());
			}
		}
		success &= runScript(myEffect->getUnApplyScript());
	}


	if(myApplier) {
		// If object appliers are being worn when we remove the effect,
		// the object will be broken and unequipped
		Object* object = myApplier->getAsObject();
		if(object && object->flagIsSet(O_WORN)) {
			object->setShotsCur(0);
			myParent->getAsPlayer()->breakObject(object, object->getWearflag());
		}
	}

	return(success);
}

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

bool EffectInfo::compute(MudObject* applier) {
	ASSERTLOG(myParent);
	if(!myEffect)
		return(false);
	myApplier = applier;
	bool retVal = runScript(myEffect->getComputeScript(), applier);
	// Incase computing results in a non permanent effect that has a negative duration!
	if(this->duration < -1) {
		duration = 60;
	}
	return(retVal);
}

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

bool EffectInfo::add() {
	ASSERTLOG(myParent);
	if(!myEffect)
		return(false);

	Creature* cParent = myParent->getAsCreature();
	if(cParent) {

		if(!myEffect->getSelfAddStr().empty())
			cParent->printColor("%s\n", cParent->doReplace(myEffect->getSelfAddStr().c_str(), cParent, myApplier).c_str());

		// TODO: replace *ACTOR* etc
		if(!myEffect->getRoomAddStr().empty() && cParent->getRoomParent())
			cParent->getRoomParent()->effectEcho(myEffect->getRoomAddStr(), cParent, myApplier);
	}
	Exit* xParent = myParent->getAsExit();
	if(xParent) {
		if(!myEffect->getRoomAddStr().empty()) {
			if(xParent->getRoom())
				xParent->getRoom()->effectEcho(myEffect->getRoomAddStr(), xParent);
			else
				std::cout << "Exit with no parent room!!!\n";
		}
	}
	BaseRoom* rParent = myParent->getAsRoom();
	if(rParent) {
		if(!myEffect->getRoomAddStr().empty())
			rParent->effectEcho(myEffect->getRoomAddStr());
	}

	return(true);
}

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

bool EffectInfo::apply() {
	ASSERTLOG(myParent);
	if(!myEffect)
		return(false);
	return(runScript(myEffect->getApplyScript()));
}

//*********************************************************************
//						preApply
//*********************************************************************

bool EffectInfo::preApply() {
	ASSERTLOG(myParent);
	if(!myEffect)
		return(false);
	return(runScript(myEffect->getPreApplyScript()));
}

//*********************************************************************
//						postApply
//*********************************************************************

bool EffectInfo::postApply(bool keepApplier) {
	bool success = false;
	ASSERTLOG(myParent);
	if(myEffect)
		success = runScript(myEffect->getPostApplyScript());

	// If you're passing in keepApplier = true, be sure you know what you're doing!
	// The effect will keep a pointer to the applier, and if the applier is removed
	// from memory (the monster is killed, the object is pawned), you'll get an
	// invalid pointer that might crash the game. Currently only equipped object
	// appliers are supported for passing in keepApplier = true.
	if(!keepApplier)
		myApplier = 0;

	return(success);
}

// End - EffectInfo functions


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


EffectInfo* MudObject::addEffect(const bstring& effect, long duration, int strength, MudObject* applier, bool show, const Creature* owner, bool keepApplier) {
	return(effects.addEffect(effect, duration, strength, applier, show, this, owner, keepApplier));
}

EffectInfo* Effects::addEffect(const bstring& effect, long duration, int strength, MudObject* applier, bool show, MudObject* pParent, const Creature* owner, bool keepApplier) {
	if(!gConfig->getEffect(effect))
		return(null);
	EffectInfo* newEffect = new EffectInfo(effect, time(0), duration, strength, pParent, owner);

	if(!newEffect->compute(applier)) {
	    delete newEffect;
	    return(NULL);
	}


	if(strength != -2)
		newEffect->setStrength(strength);
	if(duration != -2)
		newEffect->setDuration(duration);

	return(addEffect(newEffect, show, 0, keepApplier));
}

EffectInfo* MudObject::addEffect(EffectInfo* newEffect, bool show, bool keepApplier) {
	return(effects.addEffect(newEffect, show, this, keepApplier));
}

EffectInfo* Effects::addEffect(EffectInfo* newEffect, bool show, MudObject* pParent, bool keepApplier) {
	if(pParent)
		newEffect->setParent(pParent);

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

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

	// pre-apply gets called BEFORE the replaced effect gets removed
	newEffect->preApply();

	// If no existing effect, or this one will overwrite remove the old one, and add the new one
	removeEffect(newEffect->getName(), false, true);		// Don't show the removal

	// Only show if we're not overwriting an effect
	if(!oldEffect && show)
		newEffect->add();
	success &= newEffect->apply();
	effectList.push_back(newEffect);
	if(newEffect->getParent()->getAsRoom())
		newEffect->getParent()->getAsRoom()->addEffectsIndex();
	else if(newEffect->getParent()->getAsExit() && newEffect->getParent()->getAsExit()->getRoom())
		newEffect->getParent()->getAsExit()->getRoom()->addEffectsIndex();

	// post-apply gets run after everything is done
	newEffect->postApply(keepApplier);

	return(newEffect);
}

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

EffectInfo* MudObject::addPermEffect(const bstring& effect, int strength, bool show) {
	return(effects.addEffect(effect, -1, strength, NULL, show, this));
}

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

bool MudObject::removeEffect(const bstring& effect, bool show, bool remPerm, MudObject* fromApplier) {
	return(effects.removeEffect(effect, show, remPerm, fromApplier));
}

bool Effects::removeEffect(const bstring& effect, bool show, bool remPerm, MudObject* fromApplier) {
	EffectInfo* toDel = getExactEffect(effect);
	if(	toDel &&
		(toDel->getDuration() != -1 || (toDel->getDuration() == -1 && remPerm)) &&
		(!fromApplier || fromApplier == toDel->getApplier())
	)
		return(removeEffect(toDel, show));
	return(false);
}

bool MudObject::removeEffect(EffectInfo* toDel, bool show) {
	return(effects.removeEffect(toDel, show));
}

bool Effects::removeEffect(EffectInfo* toDel, bool show) {
	if(!toDel)
		return(false);

	effectList.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) {
	EffectList::iterator it;

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

//*********************************************************************
//						objectCanBestowEffect
//*********************************************************************

bool Effect::objectCanBestowEffect(const bstring& effect) {
	return(	effect != "" &&
			effect != "vampirism" &&
			effect != "porphyria" &&
			effect != "lycanthropy"
	);
}

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

bool MudObject::isEffected(const bstring& effect, bool exactMatch) const {
	return(effects.isEffected(effect, exactMatch));
}

bool MudObject::isEffected(EffectInfo* effect) const {
	return(effects.isEffected(effect));
}

// We are effected if we have an effect with this name, or an effect with a base effect
// of this name

bool Effects::isEffected(const bstring& effect, bool exactMatch) const {
	//EffectList list;
	for(EffectInfo* eff : effectList) {
		if(eff->getName() == effect || (!exactMatch && eff->hasBaseEffect(effect)))
			return(true);
	}

	return(false);
}

bool Effects::isEffected(EffectInfo* effect) const {
	for(EffectInfo* eff : effectList) {
		if(eff->getName() == effect->getName() || eff->hasBaseEffect(effect->getName()) || effect->hasBaseEffect(eff->getName()))
			return(true);
	}
	return(false);
}

//*********************************************************************
//						getBaseEffects
//*********************************************************************

const std::list<bstring>& Effect::getBaseEffects() {
    return(baseEffects);
}

// Effect - Avian Aria, Base Effects = fly, levitate
// eff = fly

// Effect - Avian Aria, Base Effects = fly, levitate
// Effect Some Jackass's Flying Song.  Base effect = fly, levitate

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

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

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

EffectInfo* MudObject::getEffect(const bstring& effect) const {
	return(effects.getEffect(effect));
}
// Returns the effect if we find one that the name matches or has
// the base effect mentioned

EffectInfo* Effects::getEffect(const bstring& effect) const {
	EffectList::const_iterator eIt;
	EffectInfo* toReturn = NULL;
	for(eIt = effectList.begin() ; eIt != effectList.end() ; eIt++) {
		if((*eIt) && ((*eIt)->getName() == effect || (*eIt)->hasBaseEffect(effect))) {
			if(!toReturn)
				toReturn = (*eIt);
			else {
				// If we have something to return, compare it, we'll return the
				// effect with the highest strength
				if((*eIt)->getStrength() > toReturn->getStrength())
					toReturn = (*eIt);
			}
		}
	}
	return(toReturn);
}

//*********************************************************************
//						getExactEffect
//*********************************************************************

EffectInfo* MudObject::getExactEffect(const bstring& effect) const {
	return(effects.getExactEffect(effect));
}

// Returns the effect with an exact name match
EffectInfo* Effects::getExactEffect(const bstring& effect) const {
	EffectList::const_iterator eIt;
	for(eIt = effectList.begin() ; eIt != effectList.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;
	EffectList::iterator eIt;
	deathtype = DT_NONE;
	for(eIt = effects.effectList.begin() ; eIt != effects.effectList.end() ;) {
		effect = (*eIt);
		// Pulse!

		ASSERTLOG(effect->getParent() == 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.effectList.erase(eIt);
		} else
			eIt++;
	}

	// pulse effects might kill them
	if(deathtype != DT_NONE && hp.getCur() < 1) {
		if(isPlayer())
			getAsPlayer()->die(deathtype);
		else
			getAsMonster()->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);

	for(Exit* exit : exits) {
		exit->pulseEffects(t);
	}
	return(true);
}

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

bool Exit::pulseEffects(time_t t) {
	effects.pulse(t, 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, MudObject* pParent) {
	EffectList::iterator it;
	EffectInfo* effect=0;
	bool pulsed=false;

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

		ASSERTLOG(effect->getParent() == pParent);
		pulsed = effect->pulse(t);

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

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

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

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

void Effects::copy(const Effects* source, MudObject* pParent) {
	EffectInfo* effect;
	EffectList::const_iterator eIt;
	for(eIt = source->effectList.begin() ; eIt != source->effectList.end() ; eIt++) {
		effect = new EffectInfo();
		(*effect) = *(*eIt);
		effect->setParent(pParent);
		effectList.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->getParent()->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.effectList.size();
	creature->print("Current Effects for %s:\n", target->getCName());
	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;
	EffectList::const_iterator eIt;
	for(eIt = effectList.begin() ; eIt != effectList.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) {
	const Object* object=0;
	std::ostringstream effStr;
	long t = time(0);

	for(EffectInfo* effect : effectList) {
		effect->updateLastMod(t);
		effStr << *effect;
		if(viewer->isStaff()) {
//			if(!effect->getBaseEffect().empty())
//				effStr << " Base(" << effect->getBaseEffect() << ")";
			effStr << "  ^WStrength:^x " << effect->getStrength();
			if(effect->getExtra()) {
				effStr << "  ^WExtra:^x " << effect->getExtra();
				
				// extra information
				if(effect->getName() == "illusion") {
					const RaceData* race = gConfig->getRace(effect->getExtra());
					if(race)
						effStr << " (" << race->getName() << ")";
				} else if(	(effect->getDuration() == -1) && (
					effect->getName() == "wall-of-force" ||
					effect->getName() == "wall-of-fire" ||
					effect->getName() == "wall-of-thorns"
				) ) {
					// permanent walls are only down for a little bit
					effStr << " (# pulses until reinstantiate)";
				}
			}
			if(effect->getApplier()) {
				object = effect->getApplier()->getAsConstObject();
				if(object)
					effStr << "  ^WApplier:^x " << object->getName() << "^x";
			}
		}
		effStr << "\n";
	}

	return(effStr.str());
}

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

void Creature::convertOldEffects() {
	Player* pPlayer = getAsPlayer();
	Monster* mMonster = getAsMonster();
	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.effectList.push_back(newEffect);
	return(true);
}

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

bool MudObject::removeOppositeEffect(const EffectInfo *effect) {
	return(effects.removeOppositeEffect(effect));
}

bool Effects::removeOppositeEffect(const EffectInfo *effect) {
	Effect* parentEffect = effect->getEffect();

    if(!parentEffect)
		return(false);

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

	return(removeEffect(parentEffect->getOppositeEffect(), true, true));
}

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

bool exitEffectDamage(const 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->getAsMonster()->addEnemy(killer);
		if(online)
			target->getAsMonster()->adjustThreat(killer, damage.get());
	}

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

	target->hp.decrease(damage.get());
	if(target->hp.getCur() < 1) {
		target->print(deathStr);
		broadcast(target->getSock(), target->getRoomParent(), 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->getAsPlayer()->die(dt);
			else
				target->getAsMonster()->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->getMaster();

	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 is engulfed by the wall of fire.\n%M burns to death!",
			"%M is engulfed by 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 is engulfed by a wall of thorns.\n%M is stabbed to death!",
			"%M is engulfed by your wall of thorns and is stabbed to death!\n"
	) )
		return(true);

	return(false);
}

//*********************************************************************
//						doReplace
//*********************************************************************

bstring Creature::doReplace(bstring fmt, const MudObject* actor, const MudObject* applier) const {
	const Creature* cActor = actor->getAsConstCreature();
	const Exit* xActor = actor->getAsConstExit();
	const Creature* cApplier = applier->getAsConstCreature();

	if(cActor) {
		fmt.Replace("*ACTOR*", cActor->getCrtStr(this, CAP).c_str());
		fmt.Replace("*LOW-ACTOR*", cActor->getCrtStr(this).c_str());
		fmt.Replace("*A-HISHER*", cActor->hisHer());
		fmt.Replace("*A-UPHISHER*", cActor->upHisHer());
	} else if(xActor) {
		fmt.Replace("*ACTOR*", xActor->getCName());
		fmt.Replace("*LOW-ACTOR*", xActor->getCName());
	}

	if(cApplier) {
		// Applier Possessive
		if(cActor == cApplier) {
			fmt.Replace("*APPLIER-POS*", cApplier->upHisHer());
			fmt.Replace("*LOW-APPLIER-POS*", cApplier->hisHer());
			fmt.Replace("*APPLIER-SELF-POS*", "Your");
			fmt.Replace("*LOW-APPLIER-SELF-POS*", "your");
		} else {
			fmt.Replace("*APPLIER-POS*", bstring(cApplier->getCrtStr(this, CAP) + "'s").c_str());
			fmt.Replace("*LOW-APPLIER-POS*", bstring(cApplier->getCrtStr(this) + "'s").c_str());
			fmt.Replace("*APPLIER-SELF-POS*", bstring(cApplier->getCrtStr(this, CAP) + "'s").c_str());
			fmt.Replace("*LOW-APPLIER-SELF-POS*", bstring(cApplier->getCrtStr(this) + "'s").c_str());
		}

		fmt.Replace("*APPLIER*", cApplier->getCrtStr(this, CAP).c_str());
		fmt.Replace("*LOW-APPLIER*", cApplier->getCrtStr(this).c_str());
		fmt.Replace("*AP-HISHER*", cApplier->hisHer());
		fmt.Replace("*AP-UPHISHER*", cApplier->upHisHer());
	}
	return(fmt);
}

//*********************************************************************
//						effectEcho
//*********************************************************************

void Container::effectEcho(bstring fmt, const MudObject* actor, const MudObject* applier, Socket* ignore) {
	Socket* ignore2 = NULL;
	if(actor->getAsConstCreature())
		ignore2 = actor->getAsConstCreature()->getSock();
	for(const Player* ply : players) {
		if(!ply || (ply->getSock() && (ply->getSock() == ignore || ply->getSock() == ignore2)) || ply->isUnconscious())
			continue;

		bstring toSend = ply->doReplace(fmt, actor, applier);
		ply->bPrint(toSend + "\n");
	}
}

//*********************************************************************
//						getPulseDelay
//*********************************************************************

int Effect::getPulseDelay() const {
    return(pulseDelay);
}

//*********************************************************************
//						runScript
//*********************************************************************

bool EffectInfo::runScript(const bstring& pyScript, MudObject* applier) {

	// Legacy: Default action is return true, so play along with that
	if(pyScript.empty())
		return(true);

	try {

	   object localNamespace( (handle<>(PyDict_New())));

		object effectModule( (handle<>(PyImport_ImportModule("effectLib"))) );

		localNamespace["effectLib"] = effectModule;

		localNamespace["effect"] = ptr(this);

		// Default retVal is true
		localNamespace["retVal"] = true;
		addMudObjectToDictionary(localNamespace, "actor", myParent);
		addMudObjectToDictionary(localNamespace, "applier", applier);



		gServer->runPython(pyScript, localNamespace);

		bool retVal = extract<bool>(localNamespace["retVal"]);
        //std::cout << "runScript returning: " << retVal << std::endl;
		return(retVal);
	}
	catch( error_already_set) {
		gServer->handlePythonError();
	}

	return(false);
}


//*********************************************************************
//						pulseCreatureEffects
//*********************************************************************
// lastUserUpdate is set in updateUsers

void Server::pulseCreatureEffects(long t) {
	Monster	*monster=0;
	const Socket *sock=0;
	Player* player=0;
	std::list<Socket*>::const_iterator it;

	for(it = sockets.begin(); it != sockets.end() ; ) {
		sock = *it;
		it++;
		if(!sock->isConnected())
			continue;
		player = sock->getPlayer();
		if(player)
			player->pulseEffects(t);
	}

	MonsterList::iterator mIt = activeList.begin();
	while(mIt != activeList.end()) {
		// Increment the iterator in case this monster dies during the update and is removed from the active list
		monster = (*mIt++);
		monster->pulseEffects(t);
	}
}

//*********************************************************************
//						pulseRoomEffects
//*********************************************************************

void Server::pulseRoomEffects(long t) {
	std::list<BaseRoom*>::iterator it;

	for(it = effectsIndex.begin() ; it != effectsIndex.end() ; ) {
		(*it)->pulseEffects(t);

		if(!(*it)->needsEffectsIndex())
			it = effectsIndex.erase(it);
		else
			it++;
	}

	lastRoomPulseUpdate = t;
}

//*********************************************************************
//						showEffectsIndex
//*********************************************************************

void Server::showEffectsIndex(const Player* player) {
	std::list<BaseRoom*>::const_iterator it;
	int i=0;

	player->printColor("^YRoom Effects Index\n");

	for(it = effectsIndex.begin() ; it != effectsIndex.end() ; it++) {
		player->print("%s\n", (*it)->fullName().c_str());
		i++;
	}

	player->print("%d room%s in effects index.\n", i, i==1 ? "" : "s");
}

//*********************************************************************
//						dmShowEffectsIndex
//*********************************************************************

int dmShowEffectsIndex(Player* player, cmd* cmnd) {
	gServer->showEffectsIndex(player);
	return(0);
}
//*********************************************************************
//						addEffectsIndex
//*********************************************************************

void BaseRoom::addEffectsIndex() {
	if(!needsEffectsIndex())
		return;
	gServer->addEffectsIndex(this);
}

void Server::addEffectsIndex(BaseRoom* room) {
	if(!this)
		return;
	// you can only be in the list once!
	std::list<BaseRoom*>::const_iterator it;
	for(it = effectsIndex.begin() ; it != effectsIndex.end() ; it++) {
		if((*it) == room)
			return;
	}

	effectsIndex.push_back(room);
}

//*********************************************************************
//						needsEffectsIndex
//*********************************************************************

bool BaseRoom::needsEffectsIndex() const {
	// any room effects?
	if(effects.effectList.size())
		return(true);

	// any exit effects?
	for(Exit* exit : exits) {
		if(exit->effects.effectList.size())
			return(true);
	}

	return(false);
}

//*********************************************************************
//						removeEffectsIndex
//*********************************************************************

bool BaseRoom::removeEffectsIndex() {
	if(needsEffectsIndex())
		return(false);
	gServer->removeEffectsIndex(this);
	return(true);
}

void Server::removeEffectsIndex(BaseRoom* room) {
	if(!this)
		return;

	std::list<BaseRoom*>::iterator it;
	for(it = effectsIndex.begin() ; it != effectsIndex.end() ; it++) {
		if((*it) == room) {
			effectsIndex.erase(it);
			return;
		}
	}
}

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

void Server::removeEffectsOwner(const Creature* owner) {
	std::list<BaseRoom*>::iterator it;

	for(it = effectsIndex.begin() ; it != effectsIndex.end() ; it++) {
		(*it)->effects.removeOwner(owner);
		for(Exit* exit : (*it)->exits) {
			exit->effects.removeOwner(owner);
		}
	}
}


//*********************************************************************
//						Effect
//*********************************************************************

Effect::Effect(xmlNodePtr rootNode) {
	xmlNodePtr curNode = rootNode->children;

    pulsed = isSpellEffect = usesStr = false;
    pulseDelay = 5;

	while(curNode) {
			 if(NODE_NAME(curNode, "Name")) xml::copyToBString(name, curNode);
		else if(NODE_NAME(curNode, "BaseEffect")) baseEffects.push_back(xml::getBString(curNode));
		else if(NODE_NAME(curNode, "Display")) xml::copyToBString(display, curNode);
		else if(NODE_NAME(curNode, "OppositeEffect")) xml::copyToBString(oppositeEffect, curNode);
		else if(NODE_NAME(curNode, "SelfAddStr")) xml::copyToBString(selfAddStr, curNode);
		else if(NODE_NAME(curNode, "SelfDelStr")) xml::copyToBString(selfDelStr, curNode);
		else if(NODE_NAME(curNode, "RoomAddStr")) xml::copyToBString(roomAddStr, curNode);
		else if(NODE_NAME(curNode, "RoomDelStr")) xml::copyToBString(roomDelStr, curNode);
		else if(NODE_NAME(curNode, "Pulsed")) xml::copyToBool(pulsed, curNode);
		else if(NODE_NAME(curNode, "PulseDelay")) xml::copyToNum(pulseDelay, curNode);
		else if(NODE_NAME(curNode, "Type")) xml::copyToBString(type, curNode);
		else if(NODE_NAME(curNode, "ComputeScript")) xml::copyToBString(computeScript, curNode);
		else if(NODE_NAME(curNode, "ApplyScript")) xml::copyToBString(applyScript, curNode);
		else if(NODE_NAME(curNode, "PreApplyScript")) xml::copyToBString(preApplyScript, curNode);
		else if(NODE_NAME(curNode, "PostApplyScript")) xml::copyToBString(postApplyScript, curNode);
		else if(NODE_NAME(curNode, "UnApplyScript")) xml::copyToBString(unApplyScript, curNode);
		else if(NODE_NAME(curNode, "PulseScript")) xml::copyToBString(pulseScript, curNode);
		else if(NODE_NAME(curNode, "Spell")) xml::copyToBool(isSpellEffect, curNode);
		else if(NODE_NAME(curNode, "UsesStrength")) xml::copyToBool(usesStr, curNode);

		curNode = curNode->next;
	}
}

//*********************************************************************
//						getPulseScript
//*********************************************************************

bstring Effect::getPulseScript() const {
    return(pulseScript);
}

//*********************************************************************
//						getUnApplyScript
//*********************************************************************

bstring Effect::getUnApplyScript() const {
    return(unApplyScript);
}

//*********************************************************************
//						getApplyScript
//*********************************************************************

bstring Effect::getApplyScript() const {
    return(applyScript);
}

//*********************************************************************
//						getPreApplyScript
//*********************************************************************

bstring Effect::getPreApplyScript() const {
    return(preApplyScript);
}

//*********************************************************************
//						getPostApplyScript
//*********************************************************************

bstring Effect::getPostApplyScript() const {
    return(postApplyScript);
}

//*********************************************************************
//						getComputeScript
//*********************************************************************

bstring Effect::getComputeScript() const {
    return(computeScript);
}

//*********************************************************************
//						getType
//*********************************************************************

bstring Effect::getType() const {
    return(type);
}

//*********************************************************************
//						isPulsed
//*********************************************************************

bool Effect::isPulsed() const {
    return(pulsed);
}

//*********************************************************************
//						isSpell
//*********************************************************************

bool Effect::isSpell() const {
    return(isSpellEffect);
}

//*********************************************************************
//						isSpell
//*********************************************************************

bool Effect::usesStrength() const {
    return(usesStr);
}

//*********************************************************************
//						getRoomDelStr
//*********************************************************************

bstring Effect::getRoomDelStr() const {
    return(roomDelStr);
}

//*********************************************************************
//						getRoomAddStr
//*********************************************************************

bstring Effect::getRoomAddStr() const {
    return(roomAddStr);
}

//*********************************************************************
//						getSelfDelStr
//*********************************************************************

bstring Effect::getSelfDelStr() const {
    return(selfDelStr);
}

//*********************************************************************
//						getSelfAddStr
//*********************************************************************

bstring Effect::getSelfAddStr() const {
    return(selfAddStr);
}

//*********************************************************************
//						getOppositeEffect
//*********************************************************************

bstring Effect::getOppositeEffect() const {
    return(oppositeEffect);
}

//*********************************************************************
//						getDisplay
//*********************************************************************

bstring Effect::getDisplay() const {
    return(display);
}

//*********************************************************************
//						hasBaseEffect
//*********************************************************************

bool EffectInfo::hasBaseEffect(const bstring& effect) const {
	return(myEffect->hasBaseEffect(effect));
}

//*********************************************************************
//						hasBaseEffect
//*********************************************************************

bool Effect::hasBaseEffect(const bstring& effect) const {
	for(const bstring& be : baseEffects) {
		if(be == effect)
			return(true);
	}
	return(false);
}

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

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

//*********************************************************************
//						EffectInfo
//*********************************************************************
// TODO: Add applier here

EffectInfo::EffectInfo(bstring pName, time_t pLastMod, long pDuration, int pStrength, MudObject* pParent, const Creature* owner):
		name(pName), lastMod(pLastMod), lastPulse(pLastMod), duration(pDuration), strength(pStrength), myParent(pParent)
{
	myEffect = gConfig->getEffect(pName);
	if(!myEffect)
		throw bstring("Can't find effect " + pName);
	setOwner(owner);
}

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

EffectInfo::EffectInfo()
{

}

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

EffectInfo::EffectInfo(xmlNodePtr rootNode) {
	xmlNodePtr curNode = rootNode->children;

	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);
		else if(NODE_NAME(curNode, "PulseModifier")) xml::copyToNum(pulseModifier, curNode);

		curNode = curNode->next;
	}

	lastPulse = lastMod = time(0);
	myEffect = gConfig->getEffect(name);

	if(!myEffect) {
		throw bstring("Can't find effect listing " + name);
	}
}

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

EffectInfo::~EffectInfo() {
}

//*********************************************************************
//						setParent
//*********************************************************************

void EffectInfo::setParent(MudObject* pParent) {
	myParent = pParent;
}

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

Effect* EffectInfo::getEffect() const {
    return(myEffect);
}

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

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

//*********************************************************************
//						getOwner
//*********************************************************************

const bstring EffectInfo::getOwner() const {
    return(pOwner);
}

//*********************************************************************
//						isOwner
//*********************************************************************

bool EffectInfo::isOwner(const Creature* owner) const {
	// currently, only players can own effects
	return(owner && owner->isPlayer() && pOwner == owner->getName());
}

//*********************************************************************
//						getLastMod
//*********************************************************************

time_t EffectInfo::getLastMod() const {
    return(lastMod);
}

//*********************************************************************
//						getDuration
//*********************************************************************

long EffectInfo::getDuration() const {
    return(duration);
}

//*********************************************************************
//						getStrength
//*********************************************************************

int EffectInfo::getStrength() const {
    return(strength);
}

//*********************************************************************
//						getExtra
//*********************************************************************

int EffectInfo::getExtra() const {
    return(extra);
}

//*********************************************************************
//						isPermanent
//*********************************************************************

bool EffectInfo::isPermanent() const {
    return(duration == -1);
}

//*********************************************************************
//						getParent
//*********************************************************************

MudObject* EffectInfo::getParent() const {
    return(myParent);
}

//*********************************************************************
//						getApplier
//*********************************************************************

MudObject* EffectInfo::getApplier() const {
    return(myApplier);
}

//*********************************************************************
//						setOwner
//*********************************************************************

void EffectInfo::setOwner(const Creature* owner) {
	if(owner)
		pOwner = owner->getName();
	else
		pOwner = "";
}

//*********************************************************************
//						setStrength
//*********************************************************************

void EffectInfo::setStrength(int pStrength) {
	if(!this)
		return;
	strength = pStrength;
}

//*********************************************************************
//						setExtra
//*********************************************************************

void EffectInfo::setExtra(int pExtra) {
	if(!this)
		return;
	extra = pExtra;
}

//*********************************************************************
//						setDuration
//*********************************************************************

void EffectInfo::setDuration(long pDuration) {
	if(!this)
		return;
	duration = pDuration;
}