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/
/*
 * afflictions.cpp
 *   Functions that handle poison/disease/curse/blind/vampirism/lycanthropy
 *   ____            _
 *  |  _ \ ___  __ _| |_ __ ___  ___
 *  | |_) / _ \/ _` | | '_ ` _ \/ __|
 *  |  _ <  __/ (_| | | | | | | \__ \
 *  |_| \_\___|\__,_|_|_| |_| |_|___/
 *
 * 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"


//*********************************************************************
//						cmdCreepingDoom
//*********************************************************************

int cmdCreepingDoom(Player* player, cmd* cmnd) {
	Creature* creature=0;
	Monster *mCreature=0;
	long	i=0, t=0;
	int		chance=0, dmg=0;

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

	if(!player->isCt()) {
		if(!player->knowsSkill("creeping-doom")) {
			player->print("You lack the ability to strike someone with creeping doom.\n");
			return(0);
		}
		if(!player->alignInOrder()) {
			player->print("%s requires you to be evil to do that.\n", gConfig->getDeity(player->getDeity())->getName().c_str());
			return(0);
		}
	}

	if(cmnd->num < 2) {
		player->print("Strike whom with creeping doom?\n");
		return(0);
	}

	creature = player->getParent()->findCreature(player, cmnd->str[1], cmnd->val[1], true, true);
	if(!creature || creature == player) {
		player->print("You don't see that here.\n");
		return(0);
	}
//	pCreature = creature->getPlayer();
	mCreature = creature->getAsMonster();

	player->smashInvis();
	player->interruptDelayedActions();

	if(!player->canAttack(creature))
		return(0);

	if(mCreature && mCreature->getType() == ARACHNID &&
		!player->checkStaff("You cannot harm arachnids with creeping-doom.\n")
	)
		return(0);
	if(	creature->getDeity() == ARACHNUS &&
		!player->checkStaff("You cannot harm followers of Arachnus with creeping-doom.\n")
	)
		return(0);


	double level = player->getSkillLevel("creeping-doom");
	i = LT(player, LT_SMOTHER);
	t = time(0);
	if(i > t && !player->isCt()) {
		player->pleaseWait(i-t);
		return(0);
	}

	player->lasttime[LT_SMOTHER].ltime = t;
	player->updateAttackTimer();
	player->lasttime[LT_SMOTHER].interval = 120L;


	chance = ((int)(level - creature->getLevel()) * 20) + bonus((int) player->piety.getCur()) * 5 + 25;
	chance = MIN(chance, 80);

	dmg = mrand((int)(level*2), (int)(level*3));

	if(mCreature)
		mCreature->addEnemy(player);

	if(!creature->isCt()) {
		if(mrand(1, 100) > chance) {
			player->print("You failed to strike %N with creeping doom.\n", creature);
			broadcast(player->getSock(), creature->getSock(), player->getRoomParent(), "%M tried to strike %N with creeping doom!", player, creature);
			creature->print("%M tried to strike you with creeping doom!\n", player);
			player->checkImprove("creeping-doom", false);
			return(0);
		}
		if(creature->chkSave(BRE, player, 0)) {
			player->printColor("^yYour creeping-doom strike was interrupted!\n");
			creature->print("You manage to partially avoid %N's creeping-doom strike.\n", player);
			dmg /= 2;
		}
	}

	player->printColor("You struck %N with creeping doom for %s%d^x damage.\n", creature, player->customColorize("*CC:DAMAGE*").c_str(), dmg);
	player->checkImprove("creeping-doom", true);
	player->statistics.attackDamage(dmg, "creeping-doom");

	creature->printColor("%M struck you with creeping doom for %s%d^x damage!\n", player, creature->customColorize("*CC:DAMAGE*").c_str(), dmg);
	broadcast(player->getSock(), creature->getSock(), player->getRoomParent(), "%M struck %N with creeping doom!", player, creature);

	// if they didn't die from the damage, curse them
	if(!player->doDamage(creature, dmg, CHECK_DIE))
		creature->addEffect("creeping-doom", 200, (int)level, player, true, player);
	return(0);
}


//********************************************************************
//						cmdPoison
//********************************************************************
// the Arachnus ability to inflict enemies with poison

int cmdPoison(Player* player, cmd* cmnd) {
	Creature* creature=0;
	Monster *mCreature=0;
	long	i=0, t=0;
	int		chance=0;
	unsigned int dur=0;

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

	if(!player->isCt()) {
		if(!player->knowsSkill("poison")) {
			if(player->getClass() == ASSASSIN || player->getSecondClass() == ASSASSIN) {
				player->print("Assassins must use envenom to poison people.\n");
			} else {
				player->print("You lack the ability to poison people.\n");
			}
			return(0);
		}
		if(!player->alignInOrder()) {
			player->print("%s requires you to be evil to do that.\n", gConfig->getDeity(player->getDeity())->getName().c_str());
			return(0);
		}
	}

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

	creature = player->getParent()->findCreature(player, cmnd->str[1], cmnd->val[1], true, true);
	if(!creature || creature == player) {
		player->print("You don't see that here.\n");
		return(0);
	}
//	pCreature = creature->getPlayer();
	mCreature = creature->getAsMonster();

	player->smashInvis();
	player->interruptDelayedActions();

	if(!player->canAttack(creature))
		return(0);

	if(mCreature && mCreature->getType() == ARACHNID &&
		!player->checkStaff("You cannot poison arachnids with this ability.\n")
	)
		return(0);
	if(	creature->getDeity() == ARACHNUS &&
		!player->checkStaff("You cannot poison followers of Arachnus with this ability.\n")
	)
		return(0);


	double level = player->getSkillLevel("poison");
	i = LT(player, LT_DRAIN_LIFE);
	t = time(0);
	if(i > t && !player->isCt()) {
		player->pleaseWait(i-t);
		return(0);
	}

	player->lasttime[LT_DRAIN_LIFE].ltime = t;
	player->updateAttackTimer();
	player->lasttime[LT_DRAIN_LIFE].interval = 120L;


	chance = ((int)(level - creature->getLevel()) * 20) + bonus((int) player->piety.getCur()) * 5 + 25;
	chance = MIN(chance, 80);
	dur = standardPoisonDuration((short)level, creature->constitution.getCur());

	if(mCreature)
		mCreature->addEnemy(player);

	if(!player->isCt()) {
		if(mrand(1, 100) > chance || creature->isPoisoned() || creature->immuneToPoison()) {
			player->printColor("^GYou fail to poison %N.\n", creature);
			creature->printColor("^G%M tried to poison you!\n", player);
			broadcastGroup(false, creature, "%M tried to poison %N.\n", player, creature);
			broadcast(player->getSock(), creature->getSock(), player->getRoomParent(), "%M tried to poison %N.", player, creature);
			player->checkImprove("poison", false);
			return(0);
		}
	}

	player->printColor("^GYou poison %N.\n", creature);
	creature->printColor("^G%M poisons you!\n", player);
	broadcastGroup(false, creature, "^G%M poisons %N.\n", player, creature);
	broadcast(player->getSock(), creature->getSock(), player->getRoomParent(), "^G%M poisons %N.", player, creature);

	if(creature->chkSave(POI, player, 0)) {
		player->print("%N partially resists your poison.\n", creature);
		creature->print("You partially resists %N's poison.\n", player);
		level = level * 2 / 3;
		dur = dur * 2 / 3;
	}

	player->checkImprove("poison", true);
	creature->poison(player, (unsigned int)level, dur);
	return(0);
}

//********************************************************************
//						poison
//********************************************************************
// the calling function is responsible for announcing the poisoning

void Creature::poison(Creature *enemy, unsigned int damagePerPulse, unsigned int duration) {
	if(immuneToPoison())
		return;
	setPoisonedBy("");

	if(enemy) {
		if(isPlayer()) {

			if(enemy->isPlayer() || enemy->isPet()) {
				setFlag(P_POISONED_BY_PLAYER);
				clearFlag(P_POISONED_BY_MONSTER);
			} else {
				setFlag(P_POISONED_BY_MONSTER);
				clearFlag(P_POISONED_BY_PLAYER);
			}

			if(enemy->isPet())
				setPoisonedBy(enemy->getMaster()->getName());
			else if(enemy->isMonster() && !enemy->flagIsSet(M_NO_PREFIX))
				setPoisonedBy((bstring)"a " + enemy->getName());
			else if(this == enemy)
				setPoisonedBy((bstring)himHer() + "self");
			else
				setPoisonedBy(enemy->getName());

		} else {

			if(enemy->isPlayer())
				setPoisonedBy(enemy->getName());
			else if(enemy->isPet())
				setPoisonedBy(enemy->getMaster()->getName());
			else if(enemy->isMonster() && !enemy->flagIsSet(M_NO_PREFIX))
				setPoisonedBy((bstring)"a " + enemy->getName());
			else
				setPoisonedBy(enemy->getName());

		}
	}

	addEffect("poison", duration, damagePerPulse, 0, false, this);
}

//********************************************************************
//						immuneToPoison
//********************************************************************

bool Creature::immuneToPoison() const {
	if(isUndead() || monType::noLivingVulnerabilities(type))
		return(true);

	if(deity == ARACHNUS)
		return(true);

	// check on mobs
	if(isMonster()) {
		if(flagIsSet(M_NO_POISON))
			return(true);
	// check on players
	} else {
		if(isStaff())
			return(true);
	}
	return(false);
}

//*********************************************************************
//						isPoisoned
//*********************************************************************

bool Creature::isPoisoned() const {
	if(immuneToPoison())
		return(false);
	return(effects.hasPoison());
}

//*********************************************************************
//						hasPoison
//*********************************************************************

bool Effects::hasPoison() const {
	EffectList::const_iterator eIt;
	for(eIt = effectList.begin() ; eIt != effectList.end() ; eIt++) {
		if((*eIt)->isPoison())
			return(true);
	}
	return(false);
}

//*********************************************************************
//						curePoison
//*********************************************************************

bool Creature::curePoison() {
    pClearFlag(P_POISONED_BY_PLAYER);
    pClearFlag(P_POISONED_BY_MONSTER);

	removeEffect("slow-poison");
	setPoisonedBy("");
	return(effects.removePoison());
}

//*********************************************************************
//						removePoison
//*********************************************************************

bool Effects::removePoison() {
	bool removed=false;
	// remove all effects flagged as poison
	EffectList::iterator eIt;
	EffectInfo *effect=0;
	for(eIt = effectList.begin() ; eIt != effectList.end() ;) {
		effect = (*eIt);

		if(effect->isPoison()) {
			removed = true;
			effect->remove();
			delete effect;
			eIt = effectList.erase(eIt);
		} else
			eIt++;
	}
	return(removed);
}

//********************************************************************
//						standardPoisonDuration
//********************************************************************

unsigned int standardPoisonDuration(short level, short con) {
	int dur = 60 * mrand(1,3) - (60*bonus((int)con)) + level*10;
	if(con > 120) {
		// a spread between 400 (50%) and 120 (0%) resistance
		double percent = 1 - (con - 120) / (680 - 120);
		percent *= dur;
		dur = (int)percent;
	}
	return(MAX(60,dur));
}

// low con, level 40:  1-3 mins
// high con, level 40: 1 min
//

//********************************************************************
//						disease
//********************************************************************
// the calling function is responsible for announcing the diseasing

void Creature::disease(Creature* enemy, unsigned int damagePerPulse) {
	if(immuneToDisease())
		return;
	addPermEffect("disease", damagePerPulse, false);
}

//********************************************************************
//						immuneToDisease
//********************************************************************

bool Creature::immuneToDisease() const {
	// no need to call noLivingVulnerabilities
	if(isMonster())
		return(true);

	if(isStaff())
		return(true);
	if(isUndead())
		return(true);

	return(false);
}

//*********************************************************************
//						isDiseased
//*********************************************************************

bool Creature::isDiseased() const {
	if(immuneToDisease())
		return(false);
	return(effects.hasDisease());
}

//*********************************************************************
//						hasDisease
//*********************************************************************

bool Effects::hasDisease() const {
	EffectList::const_iterator eIt;
	for(eIt = effectList.begin() ; eIt != effectList.end() ; eIt++) {
		if((*eIt)->isDisease())
			return(true);
	}
	return(false);
}

//*********************************************************************
//						cureDisease
//*********************************************************************

bool Creature::cureDisease() {
	return(effects.removeDisease());
}

//*********************************************************************
//						removeDisease
//*********************************************************************

bool Effects::removeDisease() {
	bool removed=false;
	// remove all effects flagged as disease
	EffectList::iterator eIt;
	EffectInfo *effect=0;
	for(eIt = effectList.begin() ; eIt != effectList.end() ;) {
		effect = (*eIt);

		if(effect->isDisease()) {
			removed = true;
			effect->remove();
			delete effect;
			eIt = effectList.erase(eIt);
		} else
			eIt++;
	}
	return(removed);
}

//*********************************************************************
//						removeCurse
//*********************************************************************
// remove curse effects

bool Creature::removeCurse() {
	return(effects.removeCurse());
}

bool Effects::removeCurse() {
	bool removed=false;
	EffectList::iterator eIt;
	EffectInfo *effect=0;
	for(eIt = effectList.begin() ; eIt != effectList.end() ;) {
		effect = (*eIt);

		if(effect->isCurse()) {
			removed = true;
			effect->remove();
			delete effect;
			eIt = effectList.erase(eIt);
		} else
			eIt++;
	}
	return(removed);
}

//********************************************************************
//						isBlind
//********************************************************************

bool Creature::isBlind() const {
	if(isMonster() || isStaff())
		return(false);
	return(isEffected("blindness"));
}

//***********************************************************************
//						isNew
//***********************************************************************
// these checks distinguish legacy vampires and werewolves from new ones.
// once these legacy classes have been removed, these functions can just
// be replaced with isEffected("vampirism") and isEffected("lycanthropy")

bool Creature::isNewVampire() const {
	if(isPlayer() && cClass == PUREBLOOD)
		return(false);
	return(isEffected("vampirism"));
}

bool Creature::isNewWerewolf() const {
	if(isPlayer() && cClass == WEREWOLF)
		return(false);
	return(isEffected("lycanthropy"));
}

//***********************************************************************
//						makeVampire
//***********************************************************************

void Creature::makeVampire() {
	addPermEffect("vampirism");
	if(isPlayer()) {
		setFlag(P_CHAOTIC);

		// make sure the master still exists and is still a vampire
		Player* player = getAsPlayer();
		if(player->getAfflictedBy() != "") {
			bool online = true;
			Player* master = gServer->findPlayer(player->getAfflictedBy());

			if(!master) {
				loadPlayer(player->getAfflictedBy().c_str(), &master);
				online = false;
			}

			if(!master || !master->isEffected("vampirism"))
				player->setAfflictedBy("");
			else {
				master->minions.push_back(getName());
				master->save(online);
			}

			if(master && !online)
				free_crt(master);
		}
	}
	if(!knowsSkill("mist"))
		addSkill("mist", 1);
	if(!knowsSkill("bite"))
		addSkill("bite", 1);
	if(!knowsSkill("hypnotize"))
		addSkill("hypnotize", 1);
}

//***********************************************************************
//						willBecomeVampire
//***********************************************************************

bool Creature::willBecomeVampire() const {
	if(!pFlagIsSet(P_PTESTER))
		return(false);

	if(level < 7 || cClass == PALADIN || isEffected("lycanthropy") || isUndead())
		return(false);
	// only evil clerics become vampires
	if(cClass == CLERIC && !(deity == ARAMON || deity == ARACHNUS))
		return(false);
	if(monType::noLivingVulnerabilities(type))
		return(false);
	return(true);
}

//***********************************************************************
//						vampireCharm
//***********************************************************************
// determines if player is a spawn of the master
// if not, it does some cleanup that should have been done elsewhere
// (an extra check to make sure everything is set properly)

bool Creature::vampireCharmed(Player* master) {
	if(!isPlayer() || !master)
		return(false);

	// if they're on their way to becoming a vampire, but arent one yet, don't
	// mess with minion or afflictedBy fields
	if(isEffected("porphyria"))
		return(false);

	Player* player = getAsPlayer();
	bool charmed = true;

	// we need to make sure the minion lists match up;
	// this won't be the case if somebody suicides and remakes

	if(charmed && (!isEffected("vampirism") || !master->isEffected("vampirism")))
		charmed = false;
	if(charmed && player->getAfflictedBy() != master->getName())
		charmed = false;

	if(charmed) {
		bool found = false;
		std::list<bstring>::iterator mIt;
		for(mIt = master->minions.begin() ; mIt != master->minions.end() && !found ; mIt++) {
			if(*mIt == player->getName())
				found = true;
		}
		if(!found)
			charmed = false;
	}

	// if they're not charmed, clean up these lists
	if(!charmed) {
		if(player->getAfflictedBy() == master->getName())
			player->setAfflictedBy("");
		master->minions.remove(player->getName());
	}
	return(charmed);
}


//********************************************************************
//						clearMinions
//********************************************************************

void Creature::clearMinions() {
	if(!isPlayer())
		return;
	Player* player = getAsPlayer(), *target=0;
	bool online = true;

	if(player->getAfflictedBy() != "") {
		target = gServer->findPlayer(player->getAfflictedBy());

		if(!target) {
			loadPlayer(player->getAfflictedBy().c_str(), &target);
			online = false;
		}

		if(target) {
			target->minions.remove(player->getName());
			target->save(online);
		}
		if(!online)
			free_crt(target);
	}

	std::list<bstring>::iterator mIt;
	for(mIt = player->minions.begin() ; mIt != player->minions.end() ; mIt++) {
		online = true;
		target = gServer->findPlayer(*mIt);

		if(!target) {
			loadPlayer((*mIt).c_str(), &target);
			online = false;
		}

		if(target) {
			if(target->getAfflictedBy() == player->getName()) {
				target->setAfflictedBy("");
				target->save(online);
			}
			if(!online)
				free_crt(target);
		}
	}
}

//********************************************************************
//						addPorphyria
//********************************************************************

bool Creature::addPorphyria(Creature *killer, int chance) {

	const RaceData* rdata = gConfig->getRace(race);
	if(rdata)
		chance -= rdata->getPorphyriaResistance();

	if(mrand(1,100) > chance)
		return(false);
	if(!willBecomeVampire())
		return(false);
	if(isEffected("porphyria") || isEffected("undead-ward") || isEffected("drain-shield"))
		return(false);
	if(!killer || !killer->isNewVampire())
		return(false);

	addEffect("porphyria", 0, 0, killer, true, this);

	// if they become a vampire, they'll be permanently charmed by their master
	if(killer->isPlayer()) {
		killer->print("You have infected %N with porphyria.\n", this);
		if(isPlayer())
			getAsPlayer()->setAfflictedBy(killer->getName());
	} else if(isPlayer())
		getAsPlayer()->setAfflictedBy("");

	return(true);

}

//********************************************************************
//						sunlightDamage
//********************************************************************
// return true if they died, false if they lived

bool Creature::sunlightDamage() {
	if(isStaff() || !isNewVampire())
		return(false);

	int dmg = hp.getMax() / 5 + mrand(1,10);

	unmist();
	wake("Terrible nightmares disturb your sleep!");
	printColor("^Y^#The searing sunlight burns your flesh!\n");
	broadcast(getSock(), getRoomParent(), "^Y%M's flesh is burned by the sunlight!", this);

	// lots of damage every 5 seconds
	hp.decrease(dmg);

	if(hp.getCur() < 1) {
		printColor("^YYou have been disintegrated!\n");
		if(isPlayer())
			getAsPlayer()->die(SUNLIGHT);
		else
			getAsMonster()->mobDeath();
		return(true);
	}
	return(false);
}

//***********************************************************************
//						makeWerewolf
//***********************************************************************

void Creature::makeWerewolf() {
	addPermEffect("lycanthropy");
	if(!knowsSkill("maul"))
		skills["maul"] = new Skill("maul", 1);
	if(!knowsSkill("frenzy"))
		skills["frenzy"] = new Skill("frenzy", 1);
	if(!knowsSkill("howl"))
		skills["howl"] = new Skill("howl", 1);
	if(!knowsSkill("claw"))
		skills["claw"] = new Skill("claw", level * 5);
}

//***********************************************************************
//						willBecomeWerewolf
//***********************************************************************

bool Creature::willBecomeWerewolf() const {
	if(!pFlagIsSet(P_PTESTER))
		return(false);
	if(level < 7 || isEffected("lycanthropy") || isUndead())
		return(false);
	if(monType::noLivingVulnerabilities(type))
		return(false);
	return(true);
}

//********************************************************************
//						addLycanthropy
//********************************************************************

bool Creature::addLycanthropy(Creature *killer, int chance) {
	if(mrand(1,100) > chance)
		return(false);
	if(!willBecomeWerewolf())
		return(false);
	if(isEffected("lycanthropy"))
		return(false);
	if(!killer || !killer->isNewWerewolf())
		return(false);

	addEffect("lycanthropy", 0, 0, killer, true, this);

	if(killer->isPlayer()) {
		killer->print("You have infected %N with lycanthropy.\n", this);
		if(isPlayer())
			getAsPlayer()->setAfflictedBy(killer->getName());
	} else if(isPlayer())
		getAsPlayer()->setAfflictedBy("");

	return(true);
}


//*********************************************************************
//						splCurePoison
//*********************************************************************
// This function allows a player to cast a curepoison spell on themself,
// another player or a monster. It will remove any poison that is in
// that player's system.

int splCurePoison(Creature* player, cmd* cmnd, SpellData* spellData) {
	Creature* target=0;

	if(	player->isPlayer() &&
		player->getClass() != CLERIC &&
		player->getClass() != PALADIN &&
		!player->isCt() &&
		spellData->how == CAST
	) {
		player->print("Your class may not cast that spell.\n");
		return(0);
	}

	// Curepoison self
	if(cmnd->num == 2) {
		target = player;
		if(spellData->how == CAST || spellData->how == SCROLL || spellData->how == WAND) {
			player->print("Cure-poison spell cast on yourself.\n");
			player->print("You feel much better.\n");
			broadcast(player->getSock(), player->getParent(), "%M casts cure-poison on %sself.",
				player, player->himHer());
		} else if(spellData->how == POTION && player->isPoisoned())
			player->print("You feel the poison subside.\n");
		else if(spellData->how == POTION)
			player->print("Nothing happens.\n");

	// Cure a monster or player
	} else {
		if(player->noPotion( spellData))
			return(0);

		cmnd->str[2][0] = up(cmnd->str[2][0]);
		target = player->getParent()->findCreature(player, cmnd->str[2], cmnd->val[2], false);

		if(!target) {
			player->print("That person is not here.\n");
			return(0);
		}

		if(checkRefusingMagic(player, target))
			return(0);

		if(spellData->how == CAST || spellData->how == SCROLL || spellData->how == WAND) {
			player->print("Cure-poison cast on %N.\n", target);
			broadcast(player->getSock(), target->getSock(), player->getParent(), "%M casts cure-poison on %N.", player, target);
			target->print("%M casts cure-poison on you.\nYou feel much better.\n", player);
		}

	}
	if(target->inCombat(false))
		player->smashInvis();

	target->curePoison();
	return(1);
}

//*********************************************************************
//						splSlowPoison
//*********************************************************************

int splSlowPoison(Creature* player, cmd* cmnd, SpellData* spellData) {
	Creature* target=0;

	// slow_poison self
	if(cmnd->num == 2) {
		target = player;
		if(spellData->how == CAST || spellData->how == SCROLL || spellData->how == WAND) {
			player->print("Slow-poison spell cast on yourself.\n");
			broadcast(player->getSock(), player->getParent(), "%M casts slow-poison on %sself.",
				player, player->himHer());
			if(!player->isPoisoned()) {
				player->print("Nothing happens.\n");
				return(0);
			}
			player->print("You feel the poison subside somewhat.\n");
		} else if(spellData->how == POTION && player->isPoisoned())
			player->print("You feel the poison subside somewhat.\n");
		else if(spellData->how == POTION)
			player->print("Nothing happens.\n");

	// Cure a monster or player
	} else {
		if(player->noPotion( spellData))
			return(0);

		cmnd->str[2][0] = up(cmnd->str[2][0]);
		// monsters are now valid targets
		target = player->getParent()->findCreature(player, cmnd->str[2], cmnd->val[2], false);

		if(!target) {
			player->print("That person is not here.\n");
			return(0);
		}

		if(checkRefusingMagic(player, target))
			return(0);

		player->print("Slow-poison cast on %N.\n", target);
		broadcast(player->getSock(), target->getSock(), player->getParent(), "%M casts slow-poison on %N.", player, target);
		target->print("%M casts slow-poison on you.\n", player);

		if(!target->isPoisoned()) {
			player->print("Nothing happens.\n");
			if(player != target)
				target->print("Nothing happens.\n");
			return(0);
		}
		target->print("You feel a little better.\n");
	}

	if(target->inCombat(false))
		player->smashInvis();

	target->addPermEffect("slow-poison");
	return(1);
}


//*********************************************************************
//						splCureDisease
//*********************************************************************

int splCureDisease(Creature* player, cmd* cmnd, SpellData* spellData) {
	Creature* target=0;

	if(player->getClass() != CLERIC &&
		player->getClass() != PALADIN &&
	    !player->isStaff() &&
		spellData->how == CAST)
	{
		player->print("Only clerics and paladins may cast that spell.\n");
		return(0);
	}

	if(cmnd->num == 2) {
		target = player;

		if(spellData->how == CAST || spellData->how == SCROLL || spellData->how == WAND) {
			player->print("Cure-disease spell cast on yourself.\n");
			player->print("Your fever subsides.\n");
			broadcast(player->getSock(), player->getParent(), "%M casts cure-disease on %sself.", player, player->himHer());
		} else if(spellData->how == POTION && player->isDiseased())
			player->print("You feel your fever subside.\n");
		else if(spellData->how == POTION)
			player->print("Nothing happens.\n");
	} else {
		if(player->noPotion( spellData))
			return(0);

		cmnd->str[2][0] = up(cmnd->str[2][0]);
		target = player->getParent()->findCreature(player, cmnd->str[2], cmnd->val[2], false);

		if(!target) {
			player->print("That's not here.\n");
			return(0);
		}

		if(checkRefusingMagic(player, target))
			return(0);

		player->print("You cure-disease cast on %N.\n", target);
		broadcast(player->getSock(), target->getSock(), player->getParent(), "%M casts cure-disease on %N.", player, target);
		target->print("%M casts cure-disease on you.\nYou feel your fever subside.\n", player);

	}
	if(target->inCombat(false))
		player->smashInvis();

	target->cureDisease();
	return(1);
}

//*********************************************************************
//						splCureBlindness
//*********************************************************************

int splCureBlindness(Creature* player, cmd* cmnd, SpellData* spellData) {
	Creature* target=0;

	if(cmnd->num == 2) {

		target = player;
		if(!player->isStaff()) {
			if(	spellData->how != POTION ||
				!player->isEffected("blindness") ||
				player->flagIsSet(P_DM_BLINDED)
			)
				player->print("Nothing happens.\n");
		}

	} else {
		if(player->noPotion( spellData))
			return(0);

		cmnd->str[2][0] = up(cmnd->str[2][0]);
		target = player->getParent()->findCreature(player, cmnd->str[2], cmnd->val[2], false);

		if(!target) {
			player->print("That's not here.\n");
			return(0);
		}


		if(checkRefusingMagic(player, target))
			return(0);


		if(spellData->how == CAST || spellData->how == SCROLL || spellData->how == WAND) {
			player->print("You cast cure blindess on %N.\n", target);
			broadcast(player->getSock(), target->getSock(), player->getParent(), "%M casts cure blindness on %N.",
				player, target);
			if(target->isPlayer()) {
				target->print("%M casts cure blindness on you.\n", player);

				if(	target->isEffected("blindness") &&
					(player->isCt() || !target->flagIsSet(P_DM_BLINDED))
				) {
					//target->print("You can see again.\n");
				} else {
					target->print("Nothing happens.\n");
				}
			}
		}


	}

	if(target->inCombat(false))
		player->smashInvis();

	if(target->isPlayer())
		if(player->isCt())
			target->clearFlag(P_DM_BLINDED);

	target->removeEffect("blindness");
	return(1);
}

//*********************************************************************
//						isCurse
//*********************************************************************

bool EffectInfo::isCurse() const {
	return(myEffect->hasBaseEffect("curse"));
}

//*********************************************************************
//						isDisease
//*********************************************************************

bool EffectInfo::isDisease() const {
	// lycanthropy is only a disease if it's not permanent - once permanent, it's
	// considered an afflication and can't be removed by cure-disease
	if(myEffect->getName() == "lycanthropy" && duration == -1)
		return(false);
	if(myEffect->hasBaseEffect("disease"))
		return(true);
	return(false);
}

//*********************************************************************
//						isPoison
//*********************************************************************

bool EffectInfo::isPoison() const {
	return(myEffect->hasBaseEffect("poison"));
}

//*********************************************************************
//						splCurse
//*********************************************************************
// This function allows a player to curse a item in their inventory

int splCurse(Creature* player, cmd* cmnd, SpellData* spellData) {
	Object	*object=0;

	if(spellData->how == CAST && player->getClass() != MAGE && player->getClass() != LICH && !player->isStaff()) {
		player->print("Only mages and liches can curse.\n");
		return(0);
	}
	if(cmnd->num < 3) {
		player->print("Curse what?\n");
		return(0);
	}

	object = player->findObject(player, cmnd, 2);

	if(!object) {
		player->print("You don't have that in your inventory.\n");
		return(0);
	}
	if(object->flagIsSet(O_CURSED)) {
		player->print("That object is already cursed.\n");
		return(1);
	}

	object->setFlag(O_CURSED);

	player->printColor("%O glows darkly.\n", object);
	broadcast(player->getSock(), player->getParent(), "%M places a curse on %1P.", player, object);

	return(1);
}

//*********************************************************************
//						splRemoveCurse
//*********************************************************************
// This function allows a player to remove a curse on all the items
// in their inventory or on another player's inventory

int splRemoveCurse(Creature* player, cmd* cmnd, SpellData* spellData) {
	Creature* target=0;
	int		i=0;
	bool	equipment=true;

	// Cast remove-curse on self
	if(cmnd->num == 2) {

		target = player;
		if(spellData->how == CAST || spellData->how == SCROLL || spellData->how == WAND) {
			player->print("Remove-curse spell cast.\n");
			broadcast(player->getSock(), player->getParent(), "%M casts remove-curse on %sself.", player, player->himHer());
		} else if(spellData->how == POTION)
			player->print("You feel relieved of burdens.\n");

	// Cast remove-curse on another player
	} else {
		if(player->noPotion( spellData))
			return(0);

		cmnd->str[2][0] = up(cmnd->str[2][0]);
		target = player->getParent()->findPlayer(player, cmnd, 2);

		if(!target) {
			player->print("That player is not here.\n");
			return(0);
		}

		// this purposely does not check the refuse list
		if(target->flagIsSet(P_LINKDEAD) && target->isPlayer()) {
			player->print("%M doesn't want that cast on them right now.\n", target);
			return(0);
		}

		player->print("Remove-curse cast on %N.\n", target);
		target->print("%M casts a remove-curse spell on you.\n", player);
		broadcast(player->getSock(), target->getSock(), player->getParent(), "%M casts remove-curse on %N.", player, target);
	}

	if(target->inCombat(false))
		player->smashInvis();

	// remove all effects flagged as cursed
	if(target->removeCurse())
		equipment = false;

	// if the remove-curse spell didn't remove a curse on the player,
	// it wants to remove a curse on their equipment
	if(equipment) {
		for(i=0; i<MAXWEAR; i++) {
			if(target->ready[i]) {
				target->ready[i]->clearFlag(O_CURSED);
				target->ready[i]->clearFlag(O_DARKNESS);
			}
		}

		if(target->flagIsSet(P_DARKNESS)) {
			for(Object* obj : target->objects) {
				obj->clearFlag(O_DARKNESS);
			}
			player->print("The aura of darkness around you dissipates.\n");
			broadcast(player->getSock(), player->getParent(), "The aura of darkness around %N dissipates.", player);
			target->clearFlag(P_DARKNESS);
		}
	}
	return(1);
}