roh/conf/area/
roh/game/talk/
roh/help/
roh/monsters/ocean/
roh/objects/ocean/
roh/player/
roh/rooms/area/1/
roh/rooms/misc/
roh/rooms/ocean/
roh/src-2.44b/
/*
 * 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-2009 Jason Mitchell, Randi Mitchell
 * 	   Contributions by Tim Callahan, Jonathan Hseu
 *  Based on Mordor (C) Brooke Paul, Brett J. Vickers, John P. Freeman
 *
 */
#include "mud.h"
#include "magic.h"
#include "effects.h"
#include "move.h"

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

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

	if(!mTarget)
		return(true);
	if(mTarget->isPet() && mTarget->following == healer)
		return(true);
	if(!mTarget->getMonster()->nearEnemy())
		return(true);
	if(target->getMonster()->isEnmCrt(healer->name))
		return(true);

	// if healer is in group with pet, they can heal
	ctag* cp = (healer->following ? healer->following : healer)->first_fol;
	while(cp) {
		if(cp->crt == healer)
			return(true);
		cp = cp->next_tag;
	}

	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->getPlayer();
	int		level=0, statBns=0, base=0, mod=0, heal=0, dmg=0;
	int		vigPet=0;
	ctag	*cp=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()) {
			cp = target->getRoom()->first_mon;
			while(cp) {
				if(cp->crt->intelligence.getCur() > 120 && cp->crt->getMonster()->isEnmCrt(target->name))
					cp->crt->getMonster()->addEnmCrt(healer);
				cp = cp->next_tag;
			}
		}

		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->following == 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 VAMPIRE:
		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->getRoom(), "%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->getRoom(), "%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->getRoom()->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->getRoom()->flagIsSet(R_OUTLAW_SAFE))
				heal = mrand(1,3);

		}
	} else {
		if(healer->isEffected("stoneskin"))
			heal /= 2;
		if(healer->flagIsSet(P_OUTLAW) && healer->getRoom()->flagIsSet(R_OUTLAW_SAFE))
			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->getPlayer();
	target = creature->getPlayer();

	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())) {
		if(player->halftolevel())
			exp = 0;
		player->addExperience(exp);
		healer->print("You %s %d experience for your deed.\n", gConfig->isAprilFools() ? "lose" : "gain", exp);
		player->checkLevel();
	}
}

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

//*********************************************************************
//						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) {
	Creature* target=0;
	int		heal=0;


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


	// Vigor 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->getPlayer()->statistics.healingCast();
			heal = getHeal(player, 0, S_VIGOR);

		} else
			heal = mrand(1, 8);

		player->hp.increase(heal);

		if(spellData->how == CAST || spellData->how == SCROLL) {
			player->print("Vigor spell cast.\n");
			broadcast(player->getSock(), player->getRoom(), "%M casts a vigor spell on %sself.",
				player, player->himHer());
			return(1);
		} else {
			player->print("You feel better.\n");
			return(1);
		}

	// Cast vigor on another player or monster
	} else {
		if(noPotion(player, spellData))
			return(0);

		cmnd->str[2][0] = up(cmnd->str[2][0]);
		target = player->getRoom()->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->getPlayer()->statistics.healingCast();
			heal = getHeal(player, target, S_VIGOR);
		} else
			heal = mrand(1, 8);

		target->hp.increase(heal);

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

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

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

	return(1);
}



//*********************************************************************
//						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) {
	Creature* target=0;
	int	heal=0;

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


	// Mend 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->getPlayer()->statistics.healingCast();
			heal = getHeal(player, 0, S_MEND_WOUNDS);

		} else
			heal = dice(2, 7, 0);

		addhp(player, heal);

		if(spellData->how == CAST || spellData->how == SCROLL) {
			player->print("Mend-wounds spell cast.\n");
			broadcast(player->getSock(), player->getRoom(), "%M casts a mend-wounds spell on %sself.",
				player, player->himHer());
			return(1);
		} else {
			player->print("You feel better.\n");
			return(1);
		}

	// Cast mend on another player or monster
	} else {
		if(noPotion(player, spellData))
			return(0);

		cmnd->str[2][0] = up(cmnd->str[2][0]);
		target = player->getRoom()->findCreature(player, cmnd->str[2], cmnd->val[2], false);
		if(!target) {
			player->print("That person is not here.\n");
			return(0);
		}

		if(!healCombatCheck(player, target))
			return(0);

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

		if(spellData->how == CAST) {

			if(player->isPlayer())
				player->getPlayer()->statistics.healingCast();
			heal = getHeal(player, target, S_MEND_WOUNDS);

		} else
			heal = dice(2, 8, 0);


		addhp(target, heal);

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

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

			return(1);
		}
	}

	return(1);
}

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

		addhp(player, heal);
		addmp(player, mpHeal);

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

			player->print("Rejuvenate spell cast.\n");
			broadcast(player->getSock(), player->getRoom(), "%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(noPotion(player, spellData))
			return(0);

		cmnd->str[2][0] = up(cmnd->str[2][0]);
		target = player->getRoom()->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->getPlayer()->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);
		}

		addhp(target, heal);
		addmp(target, 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->getRoom(), "%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->hp.restore();

		if(spellData->how == CAST || spellData->how == SCROLL) {
			if(player->isPlayer())
				player->getPlayer()->statistics.healingCast();
			player->print("Heal spell cast.\n");
			broadcast(player->getSock(), player->getRoom(), "%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(noPotion(player, spellData))
			return(0);

		creature = player->getRoom()->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->getRoom()->flagIsSet(R_SAFE_ROOM) && !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) {
				if(creature->hp.getCur() >= 4)
					creature->hp.setCur(mrand(2,4));
				else
					creature->hp.setCur(1);

				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->getRoom(), "%M's heal spell nearly kills %N!",
					player, creature);
				player->smashInvis();
				if(creature->isMonster())
					creature->getMonster()->addEnmCrt(player);
				return(1);
			}

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

			if(player->isPlayer())
				player->getPlayer()->statistics.healingCast();
			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->getRoom(), "%M casts a heal spell on %N.",
				player, creature);

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

	return(1);
}

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

void Creature::removeStatEffects() {
	Player* pThis = getPlayer();
	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 doRessLoss(int curr, int prev, bool full) {
	return(MAX(0, (prev - (full ? 0 : (prev - curr) / 5))));
}

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

int doRess(Creature* caster, cmd* cmnd, bool ress) {
	// if ress=false, it's a bloodfusion
	Player	*player = caster->getPlayer();
	int		a=0, prevLevel=0;
	bool	full=false;
	long	t=0;
	Player* playerBackup=0, *target=0;
	BaseRoom *newRoom=0;
	char	filename[80];

	strcpy(filename, "");

	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", ress ? "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",
			ress ? "resurrected" : "fused with blood");
		return(0);
	}

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

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

	if(ress) {
		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->name, ress ? "resurrect" : "bloodfuse", target->himHer());
			return(0);
		}
		if(target->getLevel() < 7) {
			caster->print("%s is not yet powerful enough to be %s.\n",
				target->name, ress ? "resurrected" : "fused with blood");
			return(0);
		}
		if(!target->flagIsSet(P_KILLED_BY_MOB)) {
			caster->print("%s does not need to be %s.\n", target->name, ress ? "resurrected" : "fused with new blood");
			return(0);
		}
	}

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

	sprintf(filename, "%s/%s.bak.xml", BACKUPPATH, target->name);
	if(!file_exists(filename)) {
		caster->print("Error loading player backup!\n");
		if(caster->isDm())
			caster->print("File: %s\n", filename);
		caster->print("Your %s attempt failed.\n", ress ? "resurrection" : "bloodfusion");
		return(0);
	}

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

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

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

	prevLevel = target->getLevel();

	// load the backed up player
	if(!loadPlayer(target->name, &playerBackup, LS_BACKUP)) {
		caster->print("File load failed.\n");
		caster->print("Your %s attempt failed.\n", ress ? "resurrection" : "bloodfusion");
		return(0);
	}

	if(target->getExperience() == playerBackup->getExperience()) {
		caster->print("Target and backup have the same experience.\n");
		caster->print("Your %s attempt failed.\n", ress ? "resurrection" : "bloodfusion");
		free_crt(playerBackup, false);
		return(0);
	}

	// Clear any stat-modifying effects from backed up player
	//normalizeStats(playerBackup);
	playerBackup->removeStatEffects();

	if(!playerBackup->statsAddUp()) {
		caster->print("Backup's stats do not add up.\n");
		caster->print("Your %s attempt failed.\n", ress ? "resurrection" : "bloodfusion");
		free_crt(playerBackup, false);
		return(0);
	}

	target->removeStatEffects();

	// set target's characteristics back to what they were before
	target->setExperience(doRessLoss(target->getExperience(), playerBackup->getExperience(), full));
	target->setLevel(playerBackup->getLevel());
	target->setActualLevel(playerBackup->getActualLevel());

	target->hp.setMax(playerBackup->hp.getMax());
	target->mp.setMax(playerBackup->mp.getMax());
	//target->pp.max = playerBackup->pp.max;
	for(Realm r = MIN_REALM; r<MAX_REALM; r = (Realm)((int)r + 1)) {
		target->setRealm(doRessLoss(target->getRealm(r), playerBackup->getRealm(r), full), r);
	}

	for(a=0; a<6; a++) {
		// don't mess with saves
		target->saves[a].chance = playerBackup->saves[a].chance;
		target->saves[a].gained = playerBackup->saves[a].gained;
	}

	target->strength.setMax(playerBackup->strength.getMax());
	target->strength.setCur(playerBackup->strength.getCur());

	target->dexterity.setMax(playerBackup->dexterity.getMax());
	target->dexterity.setCur(playerBackup->dexterity.getCur());

	target->constitution.setMax(playerBackup->constitution.getMax());
	target->constitution.setCur(playerBackup->constitution.getCur());

	target->intelligence.setMax(playerBackup->intelligence.getMax());
	target->intelligence.setCur(playerBackup->intelligence.getCur());

	target->piety.setMax(playerBackup->piety.getMax());
	target->piety.setCur(playerBackup->piety.getCur());

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

	// Free backed up player pointer from memory
	free_crt(playerBackup, false);



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

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

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


	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 = 1200L;

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

		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", ress ? "resurrected from the dead" : "fused with new blood");

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

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

	target->clearAsEnemy();
	target->save(true);
	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(doRess(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(doRess(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->getRoom(), "%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(noPotion(player, spellData))
			return(0);

		cmnd->str[2][0] = up(cmnd->str[2][0]);
		target = player->getRoom()->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->getRoom(), "%M casts a restore spell on %N.",
			player, target);

		logCast(player, target, "restore");
	}
	addhp(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;
	ctag	*cp = player->getRoom()->first_ply, *cp_tmp=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->getRoom(), "%M casts vigor on everyone in the room.\n", player);

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

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

	while(cp) {
		cp_tmp = cp->next_tag;
		if(canCastHealing(player, cp->crt, false, false, false)) {
			if(cp->crt != player)
				cp->crt->print("%M casts vigor on you.\n", player);
			addhp(cp->crt, heal);
			if(cp->crt->inCombat(false))
				player->smashInvis();
		}
		cp = cp_tmp;
	}

	return(1);
}