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/
/*
 * healmagic.cpp
 *	 Healing magic routines.
 *   ____            _
 *  |  _ \ ___  __ _| |_ __ ___  ___
 *  | |_) / _ \/ _` | | '_ ` _ \/ __|
 *  |  _ <  __/ (_| | | | | | | \__ \
 *  |_| \_\___|\__,_|_|_| |_| |_|___/
 *
 * 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 "move.h"
#include "web.h"


//*********************************************************************
//						healCombatCheck
//*********************************************************************

bool healCombatCheck(Creature* healer, Creature* target, bool print=true) {
	Monster* mTarget = target->getAsMonster();

	if(!mTarget)
		return(true);
	if(mTarget->isPet() && mTarget->getMaster() == healer)
		return(true);
	if(!mTarget->getAsMonster()->nearEnemy())
		return(true);
	if(target->getAsMonster()->isEnemy(healer))
		return(true);

	// if healer is in group with pet, they can heal
	if(healer->getGroup() == mTarget->getGroup())
		return(true);
	if(print)
		healer->print("Not while %N is in combat with someone.\n", target);
	return(false);
}


//*********************************************************************
//						getHeal
//*********************************************************************

int getHeal(Creature *healer, Creature* target, int spell) {
	Player	*pHealer = healer->getAsPlayer();
	int		level=0, statBns=0, base=0, mod=0, heal=0, dmg=0;
	int		vigPet=0;

	if(target) {
		/* Mobs with intelligence > 12 do not like people vigging their enemies and
		   will attack them. -TC */
		if(target != healer && target->isPlayer() && target->inCombat()) {
		    for(Monster* mons : target->getRoomParent()->monsters) {
                if(mons->intelligence.getCur() > 120 && mons->getAsMonster()->isEnemy(target))
                    mons->getAsMonster()->addEnemy(healer);

		    }
		}

		if(target == healer)
			target = 0;
	}

	level = healer->getLevel();
	if(	pHealer &&
		pHealer->getClass() == CLERIC &&
		(	pHealer->getSecondClass() == FIGHTER ||
			pHealer->getSecondClass() == ASSASSIN
		)
	)
		level /= 2;

	if(target)
		vigPet = target->isPet() && target->getMaster() == healer;

	switch(spell) {
	case S_VIGOR:
		base = mrand(1,8); //1d8
		break;
	case S_MEND_WOUNDS:
		base = dice(2,7,0); //2d7
		break;
	case S_REJUVENATE:
		base = dice(1,6,1); // 1d6+1
		break;
	}

	switch(healer->getClass()) {
	case CLERIC:
		statBns = bonus((int)healer->piety.getCur());

		switch(healer->getDeity()) {
		case CERIS:
			if(healer->getAdjustedAlignment() == BLOODRED || healer->getAdjustedAlignment() == ROYALBLUE) {
				healer->print("Your healing is not as effective while so far out of natural balance.\n");
				level /= 2;
			}


			mod = level / 2 + mrand(1, 1 + level / 2);
			if(healer->getAdjustedAlignment() == NEUTRAL) {
				if(spell != S_REJUVENATE)
					healer->print("Your harmonial balance gains you power with Ceris.\n");
				mod += mrand(1,4);
			}

			if(spell == S_MEND_WOUNDS)
				mod += level / 2;

			if(spell == S_REJUVENATE)
				mod = level / 3 + mrand(1, 1 + level / 3);

			break;
		case ARES:
			level /= 2;	// Ares clerics vig as if 1/2 their level

			if(healer->getAdjustedAlignment() >= BLUISH || healer->getAdjustedAlignment() <= REDDISH) {
				healer->print("Your soul is too far out of balance.\n");
				level /= 2;
			}

			mod = level / 2 + mrand(1, 1 + level / 2);

			if(spell == S_MEND_WOUNDS)
				mod += level / 2;

			break;
		case KAMIRA:
			level = (level*3)/4;
			if(healer->getAdjustedAlignment() < PINKISH) {
				healer->print("Being evil at heart is distorting your healing magic.\n");
				level /= 2;
			}
			mod = level / 2 + mrand(1, 1 + level / 2);

			if(spell == S_MEND_WOUNDS)
				mod += level / 2;
			break;
		case JAKAR:
			if(healer->getAdjustedAlignment() != NEUTRAL) {
				healer->print("Your soul is out of balance.\n");
				level /= 2;
			}

			mod = level / 2 + mrand(1, 1 + level / 2);
			if(spell == S_MEND_WOUNDS)
				mod += level / 2;

			mod = (mod*3)/4;
			break;
		}// end deity switch
		break;

	case DRUID:
		statBns = MAX(bonus((int)healer->intelligence.getCur()), bonus((int)healer->constitution.getCur()));
		mod = level/4 + mrand(1, 1 + level / 5);
		break;
	case THIEF:
	case ASSASSIN:
	case ROGUE:
	case FIGHTER:
	case BERSERKER:

	case WEREWOLF:
		statBns = bonus((int)healer->constitution.getCur());
		mod = 0;
		break;
	case MONK:
		statBns = bonus((int)healer->constitution.getCur());
		mod = mrand(1,6);
		break;

	case RANGER:
	case BARD:
	case PUREBLOOD:
		statBns = MAX(bonus((int)healer->piety.getCur()), bonus((int)healer->intelligence.getCur()));
		mod = mrand(1,6);
		break;
	case MAGE:
		statBns = MAX(bonus((int)healer->piety.getCur()), bonus((int)healer->intelligence.getCur()));
		mod = 0;
		break;

	case CARETAKER:
	case DUNGEONMASTER:
		statBns = MAX(bonus((int)healer->piety.getCur()), bonus((int)healer->intelligence.getCur()));
		mod = mrand(level/2, level);
		break;

	default:
		statBns = 0;
		mod = 0;
		break;
	} // end class switch



	// ----------------------------------------------------------------------
	// ----------------------------------------------------------------------

	// clerics and paladins of Gradius
	if(healer->getDeity() == GRADIUS) {
		statBns = bonus((int)healer->piety.getCur());

		if(pHealer && !pHealer->alignInOrder()) {
			healer->print("You are out of balance with the earth. Your healing is weakened.\n");
			level /= 2;
		}

		if(target && target->isAntiGradius()) {
			healer->print("%s is very puzzled by your healing beings of vile races.\n", gConfig->getDeity(healer->getDeity())->getName().c_str());
			mod /= 2;
		}

		if(healer->getClass() == CLERIC) {
			mod = level / 2 + mrand(1, 1 + level / 2);
			if(spell == S_MEND_WOUNDS)
				mod += level / 2;
			mod = (mod*3)/4;
		} else {
			if(spell == S_VIGOR)
				mod = level / 3 + mrand(1, 1 + level / 4);
			else
				mod = level / 2 + mrand(1, 1 + level / 3);
		}

	// clerics and paladins of Enoch and Linothan
	} else if(healer->getDeity() == ENOCH || healer->getDeity() == LINOTHAN) {
		statBns = bonus((int)healer->piety.getCur());

		if(pHealer && !pHealer->alignInOrder()) {
			healer->print("Your healing magic is weakened from lack of faith in %s.\n", gConfig->getDeity(healer->getDeity())->getName().c_str());
			level /= 2;
		}

		if(target && target->getAdjustedAlignment() < NEUTRAL && healer != target) {
			healer->print("It concerns %s that you heal the unrighteous and impure of heart.\n", gConfig->getDeity(healer->getDeity())->getName().c_str());
			healer->subAlignment(1);
			mod /= 2;
		}

		if(healer->getClass() == CLERIC) {
			mod = level / 2 + mrand(1, 1 + level / 2);
			if(spell == S_MEND_WOUNDS)
				mod += level / 2;
		} else {
			if(spell == S_VIGOR)
				mod = level / 3 + mrand(1, 1 + level / 4);
			else
				mod = level / 2 + mrand(1, 1 + level / 3);
		}

	// clerics and deathknights of Aramon and Arachnus
	} else if(healer->getDeity() == ARAMON || healer->getDeity() == ARACHNUS) {
		statBns = bonus((int)healer->piety.getCur());

		if(pHealer && !pHealer->alignInOrder())
			level /= 2;

		if(healer->getAdjustedAlignment() >= LIGHTBLUE) {

			healer->print("FOOL! You dare turn from %s's evil ways!\n", gConfig->getDeity(healer->getDeity())->getName().c_str());
			dmg = mrand(1,10);
			healer->print("You are shocked for %d damage by %s's wrath!\n", dmg, gConfig->getDeity(healer->getDeity())->getName().c_str());
			broadcast(healer->getSock(), healer->getRoomParent(), "%M doubles over in pain and wretches.\n", healer);
			healer->hp.decrease(dmg);
			mod = 0;

		} else if(target && healer != target && !vigPet) {

			if(target->getAdjustedAlignment() > LIGHTBLUE) {
				healer->print("How DARE you heal the righteous and good of heart!\n");
				dmg = mrand(1,10);
				healer->print("You are shocked for %d damage by %s's wrath!\n", dmg, gConfig->getDeity(healer->getDeity())->getName().c_str());
				broadcast(healer->getSock(), healer->getRoomParent(), "%M doubles over in pain and wretches.\n", healer);
				healer->hp.decrease(dmg);
				mod = 0;
			} else if(	healer->getDeity() == ARAMON || (
				healer->getDeity() == ARACHNUS &&
				(healer->willIgnoreIllusion() ? target->getRace() : target->getDisplayRace()) != DARKELF
			)) {
				if(healer->getDeity() == ARAMON)
					healer->print("%s disapproves of healing others than yourself.\n", gConfig->getDeity(healer->getDeity())->getName().c_str());
				else
					healer->print("%s disapproves of healing non-dark-elves.\n", gConfig->getDeity(healer->getDeity())->getName().c_str());
				mod = mrand(1, (1 + level / 5));
			}

		} else {

			if(healer->getClass() == CLERIC) {
				mod = level / 2 + mrand(1, 1 + level / 2);
				if(spell == S_MEND_WOUNDS)
					mod += level / 2;
			} else {
				mod = level / 4 + mrand(1, 1 + level / 4);
			}

		}

	}

	// ----------------------------------------------------------------------
	// ----------------------------------------------------------------------


	heal = base + statBns + mod;

	if(healer->getRoomParent()->magicBonus()) {
		if(spell == S_MEND_WOUNDS)
			heal += mrand(1, 6);
		else
			heal += mrand(1, 3);
		healer->print("The room's magical properties increase the power of your spell.\n");
	}

	if(target && healer != target) {
		if(target->isPlayer()) {
			if(target->isEffected("stoneskin"))
				heal /= 2;

			if(target->flagIsSet(P_POISONED_BY_PLAYER))
				heal = mrand(1,4);

			if(target->flagIsSet(P_OUTLAW) && target->getRoomParent()->isOutlawSafe())
				heal = mrand(1,3);

		}
	} else {
		if(healer->isEffected("stoneskin"))
			heal /= 2;
		if(healer->flagIsSet(P_OUTLAW) && healer->getRoomParent()->isOutlawSafe())
			heal = mrand (1,3);
	}

	return(MAX(1, heal));
}


void niceExp(Creature *healer, Creature *creature, int heal, int how) {
	Player	*player=0, *target=0;
	int		exp=0;

	if(how != CAST)
		return;

	// only players are allowed to use this function! It's called from creature-spells
	// though, so we have to cast
	player = healer->getAsPlayer();
	target = creature->getAsPlayer();

	if(!player || !target || healer == target)
		return;

	if(player->getDeity() == CERIS || player->getDeity() == ENOCH || player->getDeity() == LINOTHAN)
		exp = MAX(1, heal) / 4;
	else
		exp = MAX(1, heal) / 3;

	if(player->getDeity() == ARAMON)
		exp = 0;

	// also see getHeal for copy of this
	if(	player->getDeity() == ARACHNUS && (
		target->getAdjustedAlignment() > LIGHTBLUE ||
		(player->willIgnoreIllusion() ? target->getRace() : target->getDisplayRace()) != DARKELF)
	)
		exp = 0;


	if(	exp &&
		(target->hp.getCur() < target->hp.getMax()) &&
		player->halftolevel()
	) {
		player->addExperience(exp);
		healer->print("You %s %d experience for your deed.\n", gConfig->isAprilFools() ? "lose" : "gain", exp);
	}
}

//*********************************************************************
//						canCastHealing
//*********************************************************************

bool canCastHealing(Creature* player, Creature* target, bool rej=false, bool healSpell=false, bool print=true) {
	if(!healCombatCheck(player, target, print))
		return(false);

	if(target->isEffected("petrification")) {
		if(print)
			player->print("Your %s magic is ineffective.\n", rej ? "healing" : "rejuvinating");
		return(false);
	}

	// for a lich, a heal spell is offensive magic
	if(target->getClass() == LICH && healSpell)
		return(true);

	if(target->getClass() == LICH) {
		if(print)
			player->print("The aura of death around %N nullifies your %s magic.\n", target, rej ? "healing" : "rejuvinating");
		return(false);
	}
	if(!rej && target->isEffected("stoneskin")) {
		// don't check this for liches
		if(print)
			player->print("%M's stoneskin spell reflects your %s magic.\n", target, rej ? "healing" : "rejuvinating");
		return(false);
	}

	if(checkRefusingMagic(player, target, true, print))
		return(false);

	if(!rej && target->hp.getCur() >= target->hp.getMax()) {
		if(print)
			player->print("%M is at full health right now.\n", target);
		return(false);
	}
	return(true);
}

//*********************************************************************
//						castHealingSpell
//*********************************************************************

int castHealingSpell(Creature* player, cmd* cmnd, SpellData* spellData, const char* spellName, const char* feelBetter, int flag, int defaultAmount) {
	Creature* target=0;
	char	capSpellName[25];
	int		heal=0;

	strcpy(capSpellName, spellName);
	capSpellName[0] = toupper(capSpellName[0]);

	if(player->getClass() == LICH) {
		player->print("Your class prevents you from casting that spell.\n");
		return(0);
	}


	// Self
	if(cmnd->num == 2) {

		if(	player->hp.getCur() >= player->hp.getMax() &&
			!player->checkStaff("You are already at full health right now.\n") )
			return(0);

		if(spellData->how == CAST) {

			if(player->isPlayer())
				player->getAsPlayer()->statistics.healingCast();
			heal = getHeal(player, 0, flag);

		} else
			heal = defaultAmount;

		player->doHeal(player, heal);

		if(spellData->how == CAST || spellData->how == SCROLL) {
			player->print("%s spell cast.\n", capSpellName);
			broadcast(player->getSock(), player->getParent(), "%M casts a %s spell on %sself.",
				player, spellName, player->himHer());
			return(1);
		} else {
			player->print("%s\n", feelBetter);
			return(1);
		}

	// Cast vigor on another player or monster
	} 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(!canCastHealing(player, target))
			return(0);

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

		if(spellData->how == CAST) {
			if(player->isPlayer())
				player->getAsPlayer()->statistics.healingCast();
			heal = getHeal(player, target, flag);
		} else {
			heal = defaultAmount;
		}

		player->doHeal(target, heal);

		if(spellData->how == CAST || spellData->how == SCROLL || spellData->how == WAND) {
			player->print("%s spell cast on %N.\n", capSpellName, target);
			target->print("%M casts a %s spell on you.\n",  player, spellName);
			broadcast(player->getSock(), target->getSock(), player->getParent(), "%M casts a %s spell on %N.",
				player, spellName, target);

			niceExp(player, target, heal, spellData->how);
			return(1);
		}
	}

	return(1);
}

//*********************************************************************
//						splVigor
//*********************************************************************
// This function will cause the vigor spell to be cast on a player or
// another monster.

int splVigor(Creature* player, cmd* cmnd, SpellData* spellData) {
	return(castHealingSpell(player, cmnd, spellData, "vigor", "You feel better.", S_VIGOR, mrand(1, 8)));
}

//*********************************************************************
//						splMendWounds
//*********************************************************************
// This function will cause the mend spell to be cast on a player or
// another monster. It heals 2d7 hit points plus any bonuses for
// intelligence. If the player is a cleric then there is an additional
// point of healing for each level of the cleric.

int splMendWounds(Creature* player, cmd* cmnd, SpellData* spellData) {
	return(castHealingSpell(player, cmnd, spellData, "mend-wounds", "You feel much better.", S_MEND_WOUNDS, dice(2, 7, 0)));
}

//*********************************************************************
//						splRejuvenate
//*********************************************************************
// This function will cause the vigor spell to be cast on a player or
// another monster.

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

	if(!(player->getClass() == CLERIC && player->getDeity() == CERIS) && spellData->how == CAST && !player->isCt()) {
		player->print("%s does not grant you the power to cast that spell.\n", gConfig->getDeity(player->getDeity())->getName().c_str());
		return(0);
	}



	if(player->getLevel() < 13 && !player->isCt()) {
		player->print("You are not high enough in your order to cast that spell.\n");
		return(0);
	}

	if(player->mp.getCur() < 8 && spellData->how == CAST) {
		player->print("Not enough magic points.\n");
		return(0);
	}


	if(player->flagIsSet(P_NO_TICK_MP)) {
		player->print("You cannot cast that spell right now.\n");
		return(0);
	}

	// Rejuvenate self
	if(cmnd->num == 2) {

		if(	player->hp.getCur() >= player->hp.getMax() &&
			player->mp.getCur() >= player->mp.getMax() &&
			!player->checkStaff("You are already at full health and magic right now.\n") )
			return(0);

		if(spellData->how == CAST) {

			if(player->isPlayer())
				player->getAsPlayer()->statistics.healingCast();
			heal = getHeal(player, 0, S_REJUVENATE);
			mpHeal = getHeal(player, 0, S_REJUVENATE);

			if(!player->isCt()) {
				player->lasttime[LT_SPELL].ltime = time(0);
				player->lasttime[LT_SPELL].interval = 24L;
			}
			player->mp.decrease(8);

		} else {
			heal = mrand(1,8);
			mpHeal = mrand(1,8);
		}

		player->doHeal(player, heal);
		player->mp.increase(mpHeal);

		if(spellData->how == CAST || spellData->how == SCROLL) {

			player->print("Rejuvenate spell cast.\n");
			broadcast(player->getSock(), player->getParent(), "%M casts a rejuvenate spell on %sself.",
				player, player->himHer());

		} else {
			player->print("You feel revitalized.\n");
		}

	// Cast rejuvenate on another player or monster
	} 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(!canCastHealing(player, target, true))
			return(0);

		if(target->hp.getCur() >= target->hp.getMax() && target->mp.getCur() >= target->mp.getMax()) {
			player->print("%M is at full health and magic right now.\n", target);
			return(0);
		}

		if(target->flagIsSet(P_NO_TICK_MP) || target->flagIsSet(P_NO_TICK_HP)) {
			player->print("Your rejuvinating magic is ineffective.\n");
			return(0);
		}

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

		if(spellData->how == CAST && !player->isCt()) {
			player->lasttime[LT_SPELL].ltime = time(0);
			player->lasttime[LT_SPELL].interval = 24L;
		}


		if(spellData->how == CAST) {
			if(player->isPlayer())
				player->getAsPlayer()->statistics.healingCast();
			player->mp.decrease(8);
			heal = getHeal(player, target, S_REJUVENATE);
			mpHeal = getHeal(player, target, S_REJUVENATE);

		} else {
			heal = mrand(1,8);
			mpHeal = mrand(1,8);
		}

		player->doHeal(target, heal);
		target->mp.increase(mpHeal);

		if(spellData->how == CAST || spellData->how == SCROLL || spellData->how == WAND) {

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

			niceExp(player, target, (heal+mpHeal)/2, spellData->how);
		}
	}

	return(1);
}

//*********************************************************************
//						splHeal
//*********************************************************************
// This function will cause the heal spell to be cast on a player or
// another monster. It heals all hit points damage but only works 3
// times a day.

int splHeal(Creature* player, cmd* cmnd, SpellData* spellData) {
	Creature* creature=0;


	if(spellData->how == CAST && !player->isStaff()) {
		if(player->getClass() != CLERIC && player->getClass() != PALADIN && !player->isCt()) {
			player->print("Your class prohibits you from casting that spell.\n");
			return(0);
		}

		switch(player->getDeity()) {
		case ARACHNUS:
		case JAKAR:
		case GRADIUS:
		case ARES:
		case ARAMON:
		case KAMIRA:
			player->print("%s does not allow you to cast that spell.\n", gConfig->getDeity(player->getDeity())->getName().c_str());
			return(0);
		default:
			break;
		}
	}


	// Heal self
	if(cmnd->num == 2) {

		if(!dec_daily(&player->daily[DL_FHEAL]) && spellData->how == CAST && !player->isCt() && player->isPlayer()) {
			player->print("You have been granted that spell enough today.\n");
			return(0);
		}

		//addhp(player, player->hp.getMax());
		player->doHeal(player, (player->hp.getMax() - player->hp.getCur()));
		//player->hp.restore();

		if(spellData->how == CAST || spellData->how == SCROLL) {
			if(player->isPlayer())
				player->getAsPlayer()->statistics.healingCast();
			player->print("Heal spell cast.\n");
			broadcast(player->getSock(), player->getParent(), "%M casts a heal spell on %sself.", player,
				player->himHer());
			return(1);
		} else {
			player->print("You feel incredibly better.\n");
			return(1);
		}

	// Cast heal on another player or monster
	} else {
		if(player->noPotion( spellData))
			return(0);

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

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

		if(	!dec_daily(&player->daily[DL_FHEAL]) &&
			spellData->how == CAST &&
			!player->isCt() &&
			player->isPlayer()
		) {
			player->print("You have been granted that spell enough times for today.\n");
			return(0);
		}

		if(spellData->how == CAST || spellData->how == SCROLL || spellData->how == WAND) {

			if(!canCastHealing(player, creature, false, true))
				return(0);

			//		addhp(creature, creature->hp.getMax());


			if(creature->isPlayer() && creature->getClass() == LICH) {

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

				if(player->getRoomParent()->isPkSafe() && !creature->flagIsSet(P_OUTLAW)) {
					player->print("Your heal spell will harm a lich.\n");
					player->print("No killing is allowed here.\n");
					return(0);
				}
				if(creature->isEffected("resist-magic")) {
					player->print("Your spell fizzles.\n");
					if(spellData->how == CAST)
						player->subMp(20);
					return(0);
				}
			} else if(creature->isMonster() && creature->getClass() == LICH) {

				if(creature->isEffected("resist-magic")) {
					player->print("Your spell fizzles.\n");
					if(spellData->how == CAST)
						player->subMp(20);
					return(0);
				}
			}
			if(creature->getClass() == LICH) {
			    int dmg;
				if(creature->hp.getCur() >= 4)
				    dmg = creature->hp.getCur() - mrand(2,4);
				else
				    dmg = creature->hp.getCur() - 1;

				creature->hp.decrease(dmg);

				player->print("The heal spell nearly kills %N!\n",creature);

				if(creature->isPlayer())
					creature->print("%M's heal spell sucks away your life force!\n", player);

				broadcast(player->getSock(), creature->getSock(), player->getRoomParent(), "%M's heal spell nearly kills %N!",
					player, creature);
				player->smashInvis();
				if(creature->isMonster())
					creature->getAsMonster()->adjustThreat(player, dmg);
				return(1);
			}

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

			if(player->isPlayer())
				player->getAsPlayer()->statistics.healingCast();
			int healed = tMAX(creature->hp.getMax() - creature->hp.getCur() - mrand(1,4), 0);
			player->doHeal(creature, healed, 0.33);
			//creature->hp.setCur(MAX(1, creature->hp.getMax() - mrand(1,4)));

			player->print("Heal spell cast on %N.\n", creature);
			creature->print("%M casts a heal spell on you.\n", player);
			broadcast(player->getSock(), creature->getSock(), player->getRoomParent(), "%M casts a heal spell on %N.",
				player, creature);

			logCast(player, creature, "heal");
			return(1);
		}
	}

	return(1);
}

//*********************************************************************
//						removeStatEffects
//*********************************************************************

void Creature::removeStatEffects() {
	Player* pThis = getAsPlayer();
	if(pThis) {
		pThis->loseRage();
		pThis->loseFrenzy();
		pThis->losePray();
	}
	removeEffect("strength");
	removeEffect("enfeeblement");
	removeEffect("haste");
	removeEffect("slow");
	removeEffect("fortitude");
	removeEffect("weakness");
	removeEffect("insight");
	removeEffect("feeblemind");
	removeEffect("prayer");
	removeEffect("damnation");
}

//*********************************************************************
//						doRessLoss
//*********************************************************************

int doResLoss(int curr, int prev, bool full) {
	return(MAX(0, (prev - (full ? 0 : (prev - curr) / 5))));
}

//*********************************************************************
//						doRess
//*********************************************************************

int doRes(Creature* caster, cmd* cmnd, bool res) {
	// if ress=false, it's a bloodfusion
	Player	*player = caster->getAsPlayer();
	int		prevLevel=0;
	bool	full=false;
	long	t=0;
	Player *target=0;
	BaseRoom *newRoom=0;

	if(player && !player->isDm()) {
		if(player->getNegativeLevels()) {
			player->print("You cannot do that without your full life essence.\n");
			return(0);
		}
		if(player->mp.getCur() < player->mp.getMax()) {
			player->print("You must have full MP to cast that spell.\n");
			return(0);
		}
	} else {
		// a DM can set to a 100% restore instead of 80%
		if(cmnd->num == 4 && !strcasecmp(cmnd->str[3], "-full"))
			full = true;
	}


	if(cmnd->num < 2) {
		caster->print("%s?\n", res ? "Resurrect whom" : "Fuse whom with new blood");
		return(0);
	}

	cmnd->str[2][0] = up(cmnd->str[2][0]);
	target = gServer->findPlayer(cmnd->str[2]);
	if(!target) {
		caster->print("That player is not online.\n");
		return(0);
	}

	if(target->isDm() && target->flagIsSet(P_DM_INVIS) && !caster->isDm()) {
		caster->print("That player is not online.\n");
		return(0);
	}

	if(target->isStaff()) {
		caster->print("Staff characters do not need to be %s.\n",
			res ? "resurrected" : "fused with blood");
		return(0);
	}

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

	if(Move::tooFarAway(caster, target, res ? "resurrect" : "fuse with new blood"))
		return(0);

	if(res) {
		if(target->isUndead()) {
			caster->print("Undead players cannot be resurrected.\n");
			return(0);
		}
	} else {
		if(!target->isUndead()) {
			caster->print("Only undead players can be fused with new blood.\n");
			return(0);
		}
	}


	if(!caster->isDm()) {
		if(target->getLocation() != target->getLimboRoom()) {
			caster->print("%s is not in limbo! How can you %s %s?\n",
		      	target->getCName(), res ? "resurrect" : "bloodfuse", target->himHer());
			return(0);
		}
		if(target->getLevel() < 7) {
			caster->print("%s is not yet powerful enough to be %s.\n",
				target->getCName(), res ? "resurrected" : "fused with blood");
			return(0);
		}
		if(!target->flagIsSet(P_KILLED_BY_MOB)) {
			caster->print("%s does not need to be %s.\n", target->getCName(), res ? "resurrected" : "fused with new blood");
			return(0);
		}
	}

	if(target == caster) {
		caster->print("You cannot %s.\n", res ? "resurrect yourself" : "fuse yourself with new blood");
		return(0);
	}

	if(player && !player->isDm() && player->daily[DL_RESURRECT].cur == 0) {
		player->print("You have done that enough times for today.\n");
		return(0);
	}

	if(!caster->isDm() && target->daily[DL_RESURRECT].cur == 0) {
		caster->print("Players can only be %s once per 24 hours real time.\n", res ? "resurrected" : "fused with new blood");
		return(0);
	}


	caster->print("You cast a %s spell on %N.\n", res ? "resurrection" : "bloodfusion", target);

	prevLevel = target->getLevel();
	long expGain = full ? (target->statistics.getLastExperienceLoss()*4/5) : (target->statistics.getLastExperienceLoss());

	EffectInfo *effect = target->getEffect("death-sickness");
	if(effect) {
		if(full)
			target->removeEffect("death-sickness");
		else
			effect->setDuration(effect->getDuration() / 3);
	}

	target->cureDisease();
	target->curePoison();
	target->removeEffect("hold-person");
	target->removeEffect("petrification");
	target->removeEffect("confusion");
	target->removeEffect("drunkenness");

	target->clearFlag(P_KILLED_BY_MOB);
	target->setTickDamage(0);

	if(player)
		dec_daily(&player->daily[DL_RESURRECT]);
	dec_daily(&target->daily[DL_RESURRECT]);


	broadcast(caster->getSock(), caster->getRoomParent(), "%M casts a %s spell on %N.", caster, res ? "resurrection" : "bloodfusion", target);

	logn("log.resurrect", "%s(L:%d) %s %s(L%d:%d) %s.\n", caster->getCName(), caster->getLevel(),
		res ? "resurrected" : "fused", target->getCName(), prevLevel, target->getLevel(),
		res ? "from the dead" : "with new blood");

	if(res)
		broadcast("^R### %M just resurrected %s from the dead!", caster, target->getCName());
	else
		broadcast("^R### %M just fused %s with new blood!", caster, target->getCName());


	if(player && !player->isDm()) {
		t = time(0);
		caster->setFlag(P_NO_TICK_MP);
		// caster cannot tick MP for 20 mins online time
		caster->lasttime[LT_NOMPTICK].ltime = t;
		caster->lasttime[LT_NOMPTICK].interval = 120L;

		broadcast(caster->getSock(), caster->getRoomParent(), "%M collapses from exhaustion.", caster);
		caster->print("You collapse from exhaustion.\n");
		caster->knockUnconscious(120);

		caster->mp.setCur(0);
	}

	newRoom = target->getRecallRoom().loadRoom(target);
	if(newRoom) {
		target->deleteFromRoom();
		target->addToRoom(newRoom);
		target->doPetFollow();
	}

	target->print("You have been %s!\n", res ? "resurrected from the dead" : "fused with new blood");


	// Gain back 80% of lost experience

	target->addExperience(expGain);
    // See if we need to relevel
	target->checkLevel();

	target->hp.restore();
	target->mp.restore();
	target->pp.restore();

	target->computeAttackPower();
	target->computeAC();

	target->clearAsEnemy();
	target->save(true);
	updateRecentActivity();
	return(1);
}

//*********************************************************************
//						splResurrect
//*********************************************************************

int splResurrect(Creature* player, cmd* cmnd, SpellData* spellData) {

	if(spellData->how != CAST)
		return(0);

	if(!player->isDm()) {
		if(player->getClass() != CLERIC && player->getDeity() != CERIS) {
			player->print("You cannot cast that spell.\n");
			return(0);
		}
		if(!player->spellIsKnown(S_RESURRECT)) {
			player->print("You do not know that spell.\n");
			return(0);
		}
		if(player->getLevel() < 19) {
			player->print("You are not high enough level to cast that spell.\n");
			return(0);
		}
		if(player->getAdjustedAlignment() != NEUTRAL) {
			player->print("You must be neutral in order to cast that spell.\n");
			return(0);
		}
	}

	return(doRes(player, cmnd, true));
}

//*********************************************************************
//						splBloodfusion
//*********************************************************************

int splBloodfusion(Creature* player, cmd* cmnd, SpellData* spellData) {

	if(spellData->how != CAST)
		return(0);

	if(!player->isDm()) {
		if(player->getClass() != CLERIC && player->getDeity() != ARAMON) {
			player->print("You cannot cast that spell.\n");
			return(0);
		}
		if(!player->spellIsKnown(S_BLOODFUSION)) {
			player->print("You do not know that spell.\n");
			return(0);
		}
		if(player->getLevel() < 22) {
			player->print("You are not high enough level to cast that spell.\n");
			return(0);
		}
		if(player->getAdjustedAlignment() != BLOODRED) {
			player->print("You are not evil enough to cast that spell.\n");
			return(0);
		}
	}

	return(doRes(player, cmnd, false));
}

//*********************************************************************
//						splRestore
//*********************************************************************
// This function allows a player to cast the restore spell using either
// a potion or a wand.  Restore should not be a cast-able spell because
// it can restore magic points to full.

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

	if(spellData->how == CAST && player->isPlayer() && !player->isStaff()) {
		player->print("You may not cast that spell.\n");
		return(0);
	}

	// Cast restore on self
	if(cmnd->num == 2) {
		target = player;

		if(spellData->how == CAST || spellData->how == WAND) {
			player->print("Restore spell cast.\n");
			broadcast(player->getSock(), player->getParent(), "%M casts restore on %sself.", player, player->himHer());
		} else if(spellData->how == POTION)
			player->print("You feel restored.\n");

	// Cast restore on another 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);
		}


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

		logCast(player, target, "restore");
	}
	player->doHeal(target, dice(2, 10, 0));

	if(mrand(1, 100) < 34)
		target->mp.restore();

	if(player->isStaff()) {
		target->mp.restore();
		target->hp.restore();
	}

	return(1);
}

//*********************************************************************
//						splRoomVigor
//*********************************************************************

int splRoomVigor(Creature* player, cmd* cmnd, SpellData* spellData) {
	int		 heal=0;

	if(spellData->how == POTION) {
		player->print("The spell fizzles.\n");
		return(0);
	}

	if(player->getClass() != CLERIC && !player->isCt()) {
		player->print("Only clerics may cast that spell.\n");
		return(0);
	}

	player->print("You cast vigor on everyone in the room.\n");
	broadcast(player->getSock(), player->getParent(), "%M casts vigor on everyone in the room.\n", player);

	heal = mrand(1, 6) + bonus((int) player->piety.getCur());

	if(player->getRoomParent()->magicBonus()) {
		heal += mrand(1, 3);
		player->print("\nThe room's magical properties increase the power of your spell\n");
	}

	for(Player* ply : player->getRoomParent()->players) {
		if(canCastHealing(player, ply, false, false, false)) {
			if(ply != player)
				ply->print("%M casts vigor on you.\n", player);
			player->doHeal(ply, heal);
			if(ply->inCombat(false))
				player->smashInvis();
		}
	}

	return(1);
}